Pol
Pol

Reputation: 5134

Can ASP.NET Web API work on same url as MVC?

Can I have same url for both ASP.NET MVC requests returning HTML and for ASP.NET Web API returning JSON?

I see in examples routes like this: "api/{id}" but can I get rid of this api/ part and use this address in MVC (not Web API) too?

On one side this should be possible as we have content negotiation. But this way I require two routes with same address so this doesn't make sense, right?

In other words: can I have Controller and ApiController with same url? Or should I use ApiController also for HTML?

Upvotes: 7

Views: 2490

Answers (7)

Wim Coenen
Wim Coenen

Reputation: 66783

WebAPI allows you to define custom route constraints by implementing System.Web.Http.Routing.IHttpRouteConstraint.

In regular ASP.NET MVC you can do the same by implementing System.Web.Routing.IRouteConstraint.

This way, you can create routes that are only active for a certain HTTP Accept header e.g. "application/json" or "text/html".

Upvotes: 3

Oliver Picton
Oliver Picton

Reputation: 86

I may be playing devils advocate here, but I can see the point why someone would want to do something like this.

Often it is nice to have an HTML representation of an API on the same URL. This approach allows users to click around and explore an API from within the browser.

I have gotten around this in the WebAPI by using a custom message handler which 302 redirects to an MVC route.

public class HtmlMessageHandler : DelegatingHandler
{
    private List<string> contentTypes = new List<string> { "text/html", "application/html", "application/xhtml+xml" };

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Method == HttpMethod.Get && request.Headers.Accept.Any(h => contentTypes.Contains(h.ToString())))
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Redirect);

            var htmlUri = new Uri(String.Format("{0}/html",request.RequestUri.AbsoluteUri));

            response.Headers.Location = htmlUri;

            return Task.Factory.StartNew<HttpResponseMessage>(()=> response);
        }
        else 
        {
            return base.SendAsync(request, cancellationToken);
        }
    }
}

Bit of a hack maybe but it does the job and I personally like it more than a custom HTML MediaTypeFormatter (which I also tried) ;)

Upvotes: 4

Ely
Ely

Reputation: 3240

In theory, you can use web api and build a content provider that will return html (possible from razor) when the client requests text\html and json when the client requests application\json

Upvotes: 1

Erik Funkenbusch
Erik Funkenbusch

Reputation: 93464

Since the Web API uses the same routing system as MVC, if you have some way to differentiate the routes then you can use the same base url for both. You would need some kind of route constraint to map api calls to the api. This could be querystring parameter, for instance.

If your url is exactly the same, even down to querystring, then no. You're out of luck.

Upvotes: 0

tugberk
tugberk

Reputation: 58494

Previous answers have explained the situation. One thing to add is that, ASP.NET MVC or Web API, your all routes get collected under the same list.

For example, on the default project template, if you register the ASP.NET MVC route before the Web API one, you will see that requests under /api path are picked up by ASP.NET MVC route.

Upvotes: 1

Tomas Jansson
Tomas Jansson

Reputation: 23472

As stated in the previous answer you cannot do such a thing and I really can't see the point why you would want to do something like that.

But I do not agree that you should stick with one thing in a single project, if you want a clean API then I would go for the webapi and use MVC to host my pages, and at that point I would have the API in a separate folder plus under a separate route.

Upvotes: 4

Michael Edenfield
Michael Edenfield

Reputation: 28338

No, you cannot have a single URL route to two different classes. If more than one route matches an incoming request, the first one to be matched will be used.

I'm not sure why you would need to mix the two in a single project, at least not any practical reason. The ApiController can return HTML and the MVC Controller can return JSON, so just pick one and use it.

Upvotes: 1

Related Questions