Question

I have an app that uses WebApi + signalR + self-hosting. And I've added RazorEngine to enable use of cshtml views with razor syntax.

This works (see simplified code below) but this causes all WebApi calls to attempt to generate HTML through the views+razor. I want to have some WebAPi that just sends normal XML or JSON to requests from the client. E.g. maybe, one api controller to use normal XML/JSON and one api controler to generate responses using vews/razor/cshtml

Any ideas how I would go about doing this?

    class Program  {
        static void Main(string[] args)  {  
            using (WebApp.Start<Startup>(url: "http://localhost:8080/")) {
                Console.WriteLine("Started");
                Console.ReadKey();
            }
        }
    }


    public class Startup {
        public void Configuration(IAppBuilder app)  {
            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute(
                  name: "DefaultApi",
                  routeTemplate: "api/{controller}/{id}",
                  defaults: new { id = RouteParameter.Optional }
              );
            app.UseWebApi(config);
            app.UseCors(CorsOptions.AllowAll);
            app.MapSignalR();

            // RazorEngine - so WebApi can use views+razor
            GlobalConfiguration.Configuration.Formatters.Add(new HtmlMediaTypeViewFormatter());
            GlobalViews.DefaultViewParser = new RazorViewParser();
            GlobalViews.DefaultViewLocator = new RazorViewLocator();
            config.Formatters.Add(new HtmlMediaTypeViewFormatter());
        }
    }



    public class HomeController : ApiController {

        //http://localhost:8080/api/home
        public Value GetValues()  {
            return new Value() { Numbers = new int[] { 1, 2, 3 } };
        }

        //want to return just XML and not go via the view+razor+cshtml
        //Works ok for normal self-hosted webapi, but cant get to work for views+razor
        //http:localhost:8080/api/home/1
        public String Get2(int id)  {
            return "Get2() returns a string";
        }

    }


    [View("Home")]     //need this line to get the webApi views+razor to work
    public class Value  {
        public int[] Numbers { get; set; }
    }

Home.cshtml...

<html>
<head>
    <title>Hello World!</title>
</head>
<body>
    <h1>Hello World! ..</h1>
    <ul>
        @foreach (var value in Model.Numbers)
        {
            <li>@value</li>
        }
    </ul>
</body>
</html> 
Was it helpful?

Solution

There are a few ways.

A) You can just make the client send the correct accept header so that Web API negotiates the correct formatters.

b) You can customize the configuration on a per controller basis. This would allow you to define the HTML formatter only for the controllers where you want to return HTML. Here is a link on how to do per controller config: http://blogs.msdn.com/b/jmstall/archive/2012/05/11/per-controller-configuration-in-webapi.aspx

c) Don't use the return pipeline conneg for the HTML controllers. Return a HttpResposeMessage and set the Content property explicitly.

 public class HomeController : ApiController {

    //http://localhost:8080/api/home
    public HttpResponseMessage GetValues()  {
        var value = Value() { Numbers = new int[] { 1, 2, 3 } };

        return new HttpResponseMessage() {
                 Content = new ObjectContent<Value>(value, new HtmlMediaTypeViewFormatter())
             };
    }

    //want to return just XML and not go via the view+razor+cshtml
    //Works ok for normal self-hosted webapi, but cant get to work for views+razor
    //http:localhost:8080/api/home/1
    public String Get2(int id)  {
        return "Get2() returns a string";
    }

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top