Quantcast
Channel: ASPNETWebStack Issue Tracker Rss Feed
Viewing all 7215 articles
Browse latest View live

Commented Issue: Currently if a HTTP method is not supported Web API returns a 404 instead of a 405 when there are actions for other supported methods [274]

$
0
0
In the current version of Web API, when the action selector does not find a matching action for a HTTP method it returns a 404 status code even when the resource URI supports other methods (e.g. it supports GET and POST but not DELETE, PUT, etc.)

Based on the HTTP spec, this is not the correct behaviour as a 404 means that "The server has not found anything matching the Request-URI". In this case, there is a resource at the Request-URI as an operation with a supported verb succeeds so a Not Found status code is misleading and incorrect. Instead, it should return a 405 status code which means "The method specified in the Request-Line is not allowed for the resource identified by the Request-URI". This is correct as only the particular method is not supported.
Comments: Youssef passed along a repro. With this route: config.Routes.MapHttpRoute("Default", "api/{controller}/{id}", new { id = RouteParameter.Optional }); And on the controller named echo: ``` Get(int id) Delete() ``` "api/echo" is a valid url. but it only supports the Delete verb. For Get, the id parameter is required, and so that url can't invoke Get. So webapi's error here is conceptually "missing required parameter, id", and that is reported as 404. But this bug is noting that it should be reported as 405 instead because that url would work if we switched the verb to delete. Note if we make id optional on Get, like: ``` Get(int id=5) ``` than we succeed with 200.

Created Issue: TransferEncodingChunked=true doesn't work on WebHost [1124]

$
0
0
When setting response.Headers.TransferEncodingChunked, the response doesn't get chunked, and a client (Fiddler) will fail trying to read the response.

Repro 1:
public HttpResponseMessage Get()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.TransferEncodingChunked = true;
response.RequestMessage = Request;
return response;
}

Repro 2:
public HttpResponseMessage Get()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new LazyContent();
response.Headers.TransferEncodingChunked = true;
response.RequestMessage = Request;
return response;
}

public class LazyContent : HttpContent
{
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
stream.WriteByte(0);
return Task.FromResult<object>(null);
}

protected override bool TryComputeLength(out long length)
{
length = 0;
return false;
}
}

Commented Issue: TransferEncodingChunked=true doesn't work on WebHost [1124]

$
0
0
When setting response.Headers.TransferEncodingChunked, the response doesn't get chunked, and a client (Fiddler) will fail trying to read the response.

Repro 1:
public HttpResponseMessage Get()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.TransferEncodingChunked = true;
response.RequestMessage = Request;
return response;
}

Repro 2:
public HttpResponseMessage Get()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new LazyContent();
response.Headers.TransferEncodingChunked = true;
response.RequestMessage = Request;
return response;
}

public class LazyContent : HttpContent
{
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
stream.WriteByte(0);
return Task.FromResult<object>(null);
}

protected override bool TryComputeLength(out long length)
{
length = 0;
return false;
}
}

Comments: Just FYI...WebHostBufferPolicySelector is the one which causes whether the responses are chunked or not. So the above scenario, you would need to override WebHostBufferPolicySelector to add a condition for not buffering LazyContent. Following the code: ``` /// <summary> /// Determines whether the host should buffer the <see cref="HttpResponseMessage"/> entity body. /// </summary> /// <param name="response">The <see cref="HttpResponseMessage"/>response for which to determine /// whether host output buffering should be used for the response entity body.</param> /// <returns><c>true</c> if buffering should be used; otherwise a streamed response should be used.</returns> public virtual bool UseBufferedOutputStream(HttpResponseMessage response) { if (response == null) { throw Error.ArgumentNull("response"); } // Any HttpContent that knows its length is presumably already buffered internally. HttpContent content = response.Content; if (content != null) { long? contentLength = content.Headers.ContentLength; if (contentLength.HasValue && contentLength.Value >= 0) { return false; } // Content length is null or -1 (meaning not known). // Buffer any HttpContent except StreamContent and PushStreamContent return !(content is StreamContent || content is PushStreamContent); } return false; } ```

Created Unassigned: ApiExplorer doesn't return any descriptions when attribute routing is used [1125]

$
0
0
__Note__: This behavior is after today's check-in of 'direct-routes' in webapi's attribute routing.

__Scenario__: User views the apis that he is exposing.

__Issue__: HelpPage depends on ApiExplorer internally. ApiExplorer is not returning any api descriptions which are required to show up information on help page.

__Reason__: Before today's check-in, attribute routing used to create defaults for the 'controller' and 'action' variables into the defaults dictionary which ApiExplorer uses to generate descriptions, but currently we are not doing that instead only creating data tokens with the action descriptors.

__Example__ (following are the routes how they might look like in route table for the attributed controller below):

("routeName", "api/values", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [] });
("routeName", "api/values", new { }, new { httpMethod = HttpMethodConstraints[POST] }, dataTokens: new { actions = [Post(String value)] });
("routeName", "api/values/apidescriptions", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [GetSingle(Int32 id)] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[PUT] }, dataTokens: new { actions = [Put(Int32 id, String value)] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[DELETE] }, dataTokens: new { actions = [Delete(Int32 id)] });


```
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[HttpGet("apidescriptions")]
public int GetApiDescriptionsCount()
{
return Configuration.Services.GetApiExplorer().ApiDescriptions.Count;
}

[HttpGet("")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}

[HttpGet("{id}")]
public string GetSingle(int id)
{
return "value";
}

[HttpPost("")]
public void Post([FromBody]string value)
{
}

[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}

[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
```


Edited Unassigned: ApiExplorer doesn't return any descriptions when attribute routing is used [1125]

$
0
0
__Note__: This behavior is after today's check-in of 'direct-routes' in webapi's attribute routing.

__Scenario__: User views the apis that he is exposing.

__Issue__: HelpPage depends on ApiExplorer internally. ApiExplorer is not returning any api descriptions which are required to show up information on help page.

__Reason__: Before today's check-in, attribute routing used to create defaults for the 'controller' and 'action' variables into the defaults dictionary which ApiExplorer uses to generate descriptions, but currently we are not doing that instead only creating data tokens with the action descriptors.

__Example__ (following are the routes how they might look like in route table for the attributed controller below):

("routeName", "api/values", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [] });
("routeName", "api/values", new { }, new { httpMethod = HttpMethodConstraints[POST] }, dataTokens: new { actions = [Post(String value)] });
("routeName", "api/values/apidescriptions", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [GetSingle(Int32 id)] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[PUT] }, dataTokens: new { actions = [Put(Int32 id, String value)] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[DELETE] }, dataTokens: new { actions = [Delete(Int32 id)] });


```
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[HttpGet("apidescriptions")]
public int GetApiDescriptionsCount()
{
return Configuration.Services.GetApiExplorer().ApiDescriptions.Count;
}

[HttpGet("")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}

[HttpGet("{id}")]
public string GetSingle(int id)
{
return "value";
}

[HttpPost("")]
public void Post([FromBody]string value)
{
}

[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}

[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
```

__Attached__ a standalone Katana selfhost repro.

Edited Unassigned: ApiExplorer doesn't return any descriptions when attribute routing is used [1125]

$
0
0
__Note__: This behavior is after today's check-in of 'direct-routes' in webapi's attribute routing.

__Scenario__: User views the apis in that he is exposing in HelpPage.

__Issue__: HelpPage depends on ApiExplorer internally. ApiExplorer is not returning any api descriptions which are required to show up information on help page.

__Reason__: Before today's check-in, attribute routing used to create defaults for the 'controller' and 'action' variables into the defaults dictionary which ApiExplorer uses to generate descriptions, but currently we are not doing that instead only creating data tokens with the action descriptors.

__Example__ (following are the routes how they might look like in route table for the attributed controller below):

("routeName", "api/values", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [] });
("routeName", "api/values", new { }, new { httpMethod = HttpMethodConstraints[POST] }, dataTokens: new { actions = [Post(String value)] });
("routeName", "api/values/apidescriptions", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [GetSingle(Int32 id)] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[PUT] }, dataTokens: new { actions = [Put(Int32 id, String value)] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[DELETE] }, dataTokens: new { actions = [Delete(Int32 id)] });


```
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[HttpGet("apidescriptions")]
public int GetApiDescriptionsCount()
{
return Configuration.Services.GetApiExplorer().ApiDescriptions.Count;
}

[HttpGet("")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}

[HttpGet("{id}")]
public string GetSingle(int id)
{
return "value";
}

[HttpPost("")]
public void Post([FromBody]string value)
{
}

[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}

[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
```

__Attached__ a standalone Katana selfhost repro.

Edited Unassigned: ApiExplorer doesn't return any descriptions when attribute routing is used [1125]

$
0
0
__Note__: This behavior is after today's check-in of 'direct-routes' in webapi's attribute routing.

__Scenario__: User views the apis he is exposing in HelpPage.

__Issue__: HelpPage depends on ApiExplorer internally. ApiExplorer is not returning any api descriptions which are required to show up information on help page.

__Reason__: Before today's check-in, attribute routing used to create defaults for the 'controller' and 'action' variables into the defaults dictionary which ApiExplorer uses to generate descriptions, but currently we are not doing that instead only creating data tokens with the action descriptors.

__Example__ (following are how the routes might look like in route table for the attributed controller below...note the empty defaults):

("routeName", "api/values", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [] });
("routeName", "api/values", new { }, new { httpMethod = HttpMethodConstraints[POST] }, dataTokens: new { actions = [Post(String value)] });
("routeName", "api/values/apidescriptions", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[GET] }, dataTokens: new { actions = [GetSingle(Int32 id)] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[PUT] }, dataTokens: new { actions = [Put(Int32 id, String value)] });
("routeName", "api/values/{id}", new { }, new { httpMethod = HttpMethodConstraints[DELETE] }, dataTokens: new { actions = [Delete(Int32 id)] });


```
[RoutePrefix("api/values")]
public class ValuesController : ApiController
{
[HttpGet("apidescriptions")]
public int GetApiDescriptionsCount()
{
return Configuration.Services.GetApiExplorer().ApiDescriptions.Count;
}

[HttpGet("")]
public IEnumerable<string> GetAll()
{
return new string[] { "value1", "value2" };
}

[HttpGet("{id}")]
public string GetSingle(int id)
{
return "value";
}

[HttpPost("")]
public void Post([FromBody]string value)
{
}

[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}

[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
```

__Attached__ a standalone Katana selfhost repro.

Created Unassigned: WebImage.Resize can sometimes add black border [1126]

$
0
0
Sometimes resizing an image can add a black border to the output, example (images attached):
```
new WebImage("original.jpg").Resize(180, 180).Save("output.jpg");
```
A possible fix is in System.Web.Helpers/WebImage.cs:
```
private static Bitmap GetBitmapFromImage(Image image, int width, int height, bool preserveResolution = true)
{
....
+ bitmap.MakeTransparent();
```

Edited Issue: Web API with Katana host won't clear Thread.CurrentPrincipal [1012]

$
0
0
The specific problem happens when debugging unit test with Visual Studio. VS unit test will use some VS.Diagnostic.ServiceModelSlim assembly which will host a wcf service on the debugging process to communicate with VS process. The wcf service will create threads and set T.CP to current windows user.

When unit test sends request to self hosted katana web api service, it will reuse the thread that created by wcf service and won't clear the T.CP. So any request comes in will have the current windows principal. That leads to AuthorizeAttribute won't work when running under VS unit test debugging process.

The problem can be worse since web api won't clear T.CP if there is no Server.User environment set by Katana. The T.CP can be anything that is set by a previous operation.

Edited Issue: ApiExplorer ignores valid actions when there are placeholders in the route template which cannot be mapped to an action parameter [407]

$
0
0
It seems the ApiExplorer ignores valid actions when there are placeholders in the route template which cannot be mapped to an action parameter, e.g.

The ApiExplorer will not consider the route template "users/{username}/SomeAction" to be valid for action SomeAction([ModelBinder] MyUser user), that may use the value of UserName for the binding of the MyUser parameter (or not).

The action will be ignored by the ApiExplorer, although it can indeed be invoked by the framework.

Note that in the example, the action will be shown in the ApiExplorer if a default value is provided for placeholder {username}, as a possible workaround.

Edited Issue: Enable FxCop for System.Net.Http.Formatting.NetCore [614]

$
0
0
It currently doesn't pass CodeAnalysis (and CodeAnalysis is disabled project-wide).

Edited Issue: [MQ] Ensure the CA1804 FxCop rule runs on the runtime [548]

$
0
0
FxCop violations are being ignored by build.cmd. We need to figure out why and resolve the issue.

Edited Issue: Route specific message handlers are not getting traced [222]

$
0
0
Tracing is happening for message handlers common for all routes, but not for the route specific ones.

Attached a standalone Xunit repro.

Edited Issue: MediaTypeFormatterTracer doesn't pass MediaTypeMappings to inner formatter [849]

$
0
0
The particular issue happens when supporting $format to ODataMediaTypeFormatter.

The controller configuration won't work with tracing enabled:

public class ODataFormatQueryAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
var formatters = controllerSettings.Formatters.Where(f =>
!f.MediaTypeMappings.OfType<QueryStringMapping>().Any(m => m.QueryStringParameterName == "$format"));

formatters.ToList().ForEach(f =>
{
f.AddQueryStringMapping("$format", "atom", "application/atom+xml");
f.AddQueryStringMapping("$format", "json", "application/json");
f.AddQueryStringMapping("$format", "xml", "application/xml");
});
}
}

The reason is because MediaTypeFormatterTracer doesn't pass MediaTypeMappings to inner formatter. When call GetPerRequestFormatterInstance, it will delegate to inner formatter to create a new one to negotiate. The new one will copy from the inner formatter which doesn't has the mappings.

Edited Feature: We should open up the configuration.Services to allow user register their custom services [873]

$
0
0
Today if one tries to add a custom service to the configuration.Services bag, it will throw exception saying that it does not support unknown services.

We should open this up so that people don't have to use configuration.Property bag to store those config wide settings. Also, because we will use DI first, custom service type will get the benefit.

Edited Issue: HttpActionContext.ActionArguments dictionary should use OrdinalIgnoreCase comparer. [696]

$
0
0
Currently the HttpActionContext.ActionArguments uses the default dictionary initializer, which means that the keys are looked up using a case-sensitive comparer.

This conflicts with the stated design of Web APIs parameter binding which is supposed to be case-insensitive. In fact, WebAPI's route parameters are case-insensitive.

Having ActionArguments be case-sensitive means that it's more difficult than necessary to write code that can correctly retrieve values. For example, say I have an "id" action argument. The routing behavior means that I can have any casing for the parameter and things will still work regardless of the casing in the route configuration. I can have public TResult Get(int ID) or public TResult Get(int id), and they'll get routed either way.

But if I want to write a filter that inspects those action arguments, I cannot just write actionContext.ActionArguments["Id"] since the lookup is case sensitive.

While this would technically be a breaking change, I think it's one worth taking since it brings the behavior more inline with the rest of routing as well as the general case-aware (but case-insensitive) behavior when it comes to method parameters.

Edited Issue: Model binding of route wildcard broken in Web API [718]

$
0
0
A route like this:

routes.MapHttpRoute(
"KuduVirtualFileSystem",
"api/{segment}/{*path}",
defaults: new { controller = "demo" });

and a Web Api controller action like this:

public async Task<HttpResponseMessage> GetItem(string segment, string path = null)

fails a request like this (no path component)

http:/..../api/segment

but works for a non-empty path component like this:

http:/.../api/segment/path

The exception is as follows:

{"Message":"An error has occurred.","ExceptionMessage":"Object reference not set to an instance of an object.","ExceptionType":"System.NullReferenceException","StackTrace":" at System.Web.Http.ValueProviders.Providers.RouteDataValueProvider.<GetRoutes>d__4.MoveNext()\r\n at System.Web.Http.ValueProviders.Providers.NameValuePairsValueProvider.InitializeValues(IEnumerable`1 nameValuePairs)\r\n at System.Web.Http.ValueProviders.Providers.NameValuePairsValueProvider.<>c__DisplayClass8.<.ctor>b__4()\r\n at System.Lazy`1.CreateValue()\r\n at System.Lazy`1.LazyInitValue()\r\n at System.Lazy`1.get_Value()\r\n at System.Web.Http.ValueProviders.Providers.NameValuePairsValueProvider.GetValue(String key)\r\n at System.Web.Http.ValueProviders.Providers.CompositeValueProvider.GetValue(String key)\r\n at System.Web.Http.ModelBinding.Binders.TypeConverterModelBinder.BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)\r\n at System.Web.Http.Controllers.HttpActionContextExtensions.Bind(HttpActionContext actionContext, ModelBindingContext bindingContext, IEnumerable`1 binders)\r\n at System.Web.Http.ModelBinding.Binders.CompositeModelBinder.TryBind(HttpActionContext actionContext, ModelBindingContext bindingContext)\r\n at System.Web.Http.ModelBinding.Binders.CompositeModelBinder.BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)\r\n at System.Web.Http.ModelBinding.ModelBinderParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)\r\n at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(HttpParameterBinding parameterBinder)\r\n at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()\r\n at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken)"}

Attached is a repro showing that it works in MVC and not in Web API

Edited Issue: Fix FxCop violations for Microsoft.AspNet.Mvc.Facebook assembly [860]

$
0
0
The facebook assembly is not currently running with the Strict ruleset for code analysis like the rest of our product assemblies.

This line:

<CodeAnalysisRuleSet>..\Strict.ruleset</CodeAnalysisRuleSet>

needs to be added to the csproj file and all violations need to be fixed or suppressed.

Edited Issue: ApiExplorer not providing descriptions for route parameters not present on the action [865]

$
0
0
For the following ValuesController and default Web API route, the help page is getting generated as expected.

public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}

// GET api/values/5
public string Get(int id)
{
return "value";
}

// POST api/values
public void Post([FromBody]string value)
{
}

// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}

// DELETE api/values/5
public void Delete(int id)
{
}
}

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

However, whenever I change my route to the following, the help page does not show the ValuesController details totally.(Its actually the ApiExplorer which is not giving back the ApiDescriptions which HelpPage uses to display)

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{version}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

I debugged this and noticed that this is probably due the matching check that the ApiExplorer does for each action against a route. For example, if my action was like below(‘version’ parameter), then the ApiDescription is created…but I do not want to have a version parameter in my action…

// GET api/values/5
public string Get(int id, string version)
{
return "value";
}

Expected:
Help page should be displayed...there could be any number of route parameters in a url, but for my action to be selected, only a subset of those is required, so in this case my action should still be displayed in the help page..

Edited Feature: [Routing] Improve our versioning story with same controller name but under different namespace [834]

$
0
0
If one has two TestController types under different namespace, it is very hard to pick the right one based on the route it came on. Our default controller selector would throw exceptions on multiple matching types.

public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
if (request == null)
{
throw Error.ArgumentNull("request");
}

string controllerName = GetControllerName(request);
if (String.IsNullOrEmpty(controllerName))
{
throw new HttpResponseException(request.CreateErrorResponse(
HttpStatusCode.NotFound,
Error.Format(SRResources.ResourceNotFound, request.RequestUri),
Error.Format(SRResources.ControllerNameNotFound, request.RequestUri)));
}

HttpControllerDescriptor controllerDescriptor;
if (_controllerInfoCache.Value.TryGetValue(controllerName, out controllerDescriptor))
{
return controllerDescriptor;
}

ICollection<Type> matchingTypes = _controllerTypeCache.GetControllerTypes(controllerName);

// ControllerInfoCache is already initialized.
Contract.Assert(matchingTypes.Count != 1);

if (matchingTypes.Count == 0)
{
// no matching types
throw new HttpResponseException(request.CreateErrorResponse(
HttpStatusCode.NotFound,
Error.Format(SRResources.ResourceNotFound, request.RequestUri),
Error.Format(SRResources.DefaultControllerFactory_ControllerNameNotFound, controllerName)));
}
else
{
// multiple matching types
throw CreateAmbiguousControllerException(request.GetRouteData().Route, controllerName, matchingTypes);
}
}

If the routes look like, where user want to create the right TestController based which route the request came, it is difficult to do today. We should improve the story here.

config.Routes.MapHttpRoute(
name: "HelloV1",
routeTemplate: "api/v1/hello",
defaults: new { id = RouteParameter.Optional, controller = "Test", action = "Hello" }
);

// Controller: MvcApplication1.Controllers.V2.Test
config.Routes.MapHttpRoute(
name: "HelloV2",
routeTemplate: "api/v2/hello_v2",
defaults: new { id = RouteParameter.Optional, controller = "Test", action = "Hello_V2" }
);

Viewing all 7215 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>