Closed bartosz-jarmuz closed 5 years ago
Let's make sure we're on the same page first. I see information for both convention-based routing and attribute-based routing. Which one are you using or do you want to use? It also appears that you're using MVC with Razor. They can be used together, I just want to make sure I understand they are both being used and what part of the question maps to what.
When you version by URL segment, that route parameter number be supplied. I don't see the {version}
parameter in your action method and it's template doesn't seem to match the convention-based route. Regardless, I would expect @Url.HttpRouteUrl
to require the {version}
parameter; something like: { new { version = "1.0", telemetryKey = Guid.NewGuid() }
.
How you determine the value for version
is up to you. The UrlHelper appears to be being used from the MVC side so as a client, there isn't really a magic way to know what the API version should be. Telemetry APIs tend to be version-neutral. If that case applies to you, then consider making your API version neutral.
Hello, Yeah, I tried both approaches (originally just the namespacec convention, then with the ApiVersion attribute, then both together). It worked the same way in all cases.
I am indeed using MVC with Razor - basically, parts of my webapp communicate with the API controllers rather than mvc controllers. So yes, it is being used from the client.
My action method does not have the version parameter, because I assume it is enough if its set on the controller, by controller being in the proper namespace. However, now that I think about it, indeed I am being stupid not passing the version to the UrlHelper in any way.
I had a quick try and it seems to work when I add the version parameter. Thank you very much. Is there any way to default to a certain/latest version if parameter is not specified?
One thing - could you quickly elaborate on 'Telemetry APIs tend to be version-neutral'?
Thanks again
Is there any way to default to a certain/latest version if parameter is not specified?
Using the URL segment method, not really. There isn't a way to default a value in the middle of a path. If you simply always want the latest, you can achieve your goal with floating, double routes. First, update your configuration like so:
public static void Register(HttpConfiguration config)
{
config.AddApiVersioning(opt =>
{
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.ApiVersionSelector = new CurrentImplementationApiVersionSelector(opt);
opt.Conventions.Add(new VersionByNamespaceConvention());
});
// omitted for brevity
Now update your controller to:
[RoutePrefix("api")]
public class ProgramsController : ApiController
{
// api/programs/{key}/versions/latest
// api/v{version}/programs/{key}/versions/latest
[HttpGet]
[Route("v{version:apiVersion}/programs/{telemetryKey}/versions/latest")]
[Route("programs/{telemetryKey}/versions/latest", Name = "LatestVersionInfoRoute")]
public async Task<LatestVersionResponse> GetLatestVersionInfo(Guid telemetryKey)
{
//do stuff
}
}
How this works:
AssumeDefaultVersionWhenUnspecified = true
a client can make a request without providing an API version (this was really meant for backward compatibility)I'm not a fan of this technique or the URL segment method in general, but it will work. Since you seem to own both the client and server side of the API, some of the potential issues are less worrisome.
...could you quickly elaborate on 'Telemetry APIs tend to be version-neutral'?
Telemetry and other health check type APIs are common. Many of these APIs do not vary between versions and/or have no versioning at all. These APIs can be version-neutral, meaning that they accept any and all API versions, including none at all. Consider the following:
[ApiVersionNeutral]
[RoutePrefix("api/ping")]
public class PingController : ApiController
{
[Route]
public IHttpActionResult Get() => Ok();
}
This API always responds to api/ping
no matter the API version. This type of API might be used simply to verify that the endpoint can be reached and never changes between API versions. This behavior tends to be common with telemetry APIs too. If that's your scenario, API version-neutral might work for you here.
Kind in mind that a given route cannot be both versioned and version-neutral at the same time. When you opt into this behavior, the expectation is that the API doesn't have specific needs about a particular API version. If you want to know the API version requested, you can do something like this for the URL segment method:
[ApiVersionNeutral]
[RoutePrefix("api")]
public class PingController : ApiController
{
[Route("ping")]
[Route("v{version:apiVersion}/ping")]
public IHttpActionResult Get(ApiVersion apiVersion) => Ok();
}
When GET api/v1/ping
is requested, the apiVersion
will be 1.0
. When GET api/ping
is requested, the apiVersion
will be null
or ApiVersioningOptions.DefaultApiVersion
depending on your configuration.
I hope that helps.
Thank you very much, for both parts of the answer - especially that the second one does not even concern your great library. I will close this issue. I'll just add that I really admire the usefulness of this plugin, as well as great documentation and support. Cheers!
Hello, I have an WebApi2 API controller which looks more or less like that:
unfortunately, the URL Helpers returns an empty string for this route
@Url.HttpRouteUrl("LatestVersionInfoRoute", new { telemetryKey = Guid.NewGuid()})
The route I expect is
api/v1/programs/[THE GUID]/versions/latest
Other than that the URL helper problem, everything works OK, i.e. swagger documentation shows proper route (and the route works) - both with namespace convention and with [ApiVersion] attribute.
When I change the 'variable' apiVersion part of the prefix to a constant 'v1', then the routing works OK.
The Register method in WebApiConfig.cs class contains the following code
Is there a way to use the UrlHelpers? If not, what is the alternative, if I want to call the webapi endpoints from within views in my MVC app?