zoukankan      html  css  js  c++  java
  • How to combine WCF Route and MVC Route to work together.

    WCF REST Services Inside MVC Projects

    Recently I blogged about WCF REST services with no svc file and no config. In this post I also discussed the pros/cons of WCF services as compared to using MVC controller actions for web services and I made the case that, in many instances, WCF REST services is better than using the MVC infrastructure because WCF provides:

    • a more RESTful API with less work
    • a convenient automatic help page to assist consumers of your service
    • automatic format selection (i.e., xml/json) depending on HTTP headers

    In any case, using both WCF REST services and MVC-style web services are *both* quite convenient – and you don’t have to choose. You can use both. In fact, you can use both inside the same web application project. However, a recent question on StackOverflow illustrates that you have to be careful how you set up your routing in order to make WCF REST services work inside MVC applications.

    If you have a look at the question on StackOverflow, you’ll see the routes were originally set up like this:

       1:  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
       2:              
       3:  routes.Add(new ServiceRoute("Person", new WebServiceHostFactory(), typeof(PersonService)));
       4:   
       5:  routes.MapRoute(
       6:      "Default", // Route name
       7:      "{controller}/{action}/{id}", // URL with parameters
       8:      new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
       9:  );

    The service route was for the WCF Service (using no *.svc file) and the last route was the standard MVC route. In most of the cases this works fine. Navigation to the root correctly lands on the HomeController’s Index method. Navigation to “/Person/help” correctly goes to the WCF REST help page and the WCF REST service can be invoked just fine. However, the action links were not correct.  When formulating a simple action link like this:

       1:  <%: Html.ActionLink("Home", "Index", "Home")%>

    The resulting URL being produced was: “/Person?action=Index&controller=Home” which was clearly not correct. It’s hitting the first route and thinking it should just put “Person” for the first segment. It then cannot match the “controller” or “action” tokens so it just puts them in the query string. It will attempt to go to the service but the URI is incorrect so, if it’s a WCF REST service, you’ll just get the default help page.

    Of course, we know that the *order* matters for routing so what if we put the MVC route first and the service route second? In this case, we run into a different problem. If the first URI segment is “Person” then it will try to match that as the controller name and you’ll get a 404 or, if you’re using a controller factory, your IoC container won’t be able to find a controller named “PersonController”.

    So how can we get the WCF REST service route and the MVC routes to play nice with each other? The simple answer: use a route contraint:

       1:  routes.MapRoute(
       2:      "Default", // Route name
       3:      "{controller}/{action}/{id}", // URL with parameters
       4:      new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
       5:      new { controller = "^(?!Person).*" }
       6:  );
       7:   
       8:  routes.Add(new ServiceRoute("Person", new WebServiceHostFactory(), typeof(PersonService)));

    Notice on line #5 above, we add a route constraint so that it will try to use the MVC route first as long as the first segment (where the “controller” token is positioned) is not the “Person” string which matches where we want our WCF REST service to be. If it is “Person”, then it will fall through to the service route and correctly point to our WCF REST service.

    One other interesting note when using service routes in MVC applications – anytime you’re going beyond the default MVC routes, I highly recommend you unit test your routes. This can be done very easily with the TestHelper that comes with MvcContrib. It makes it trivial to unit test routes like this:

       1:  [TestMethod]
       2:  public void default_path_should_be_able_to_match_controller()
       3:  {
       4:      "~/".Route().ShouldMapTo<HomeController>();            
       5:  }

    The unfortunate caveat here is that you cannot use this when you’re combining service routes. If you do, you’ll get this exception when you initialize your routes at the start of the unit test by invoking the static RegisterRoutes() method: “System.InvalidOperationException: System.InvalidOperationException: 'ServiceHostingEnvironment.EnsureServiceAvailable' cannot be invoked within the current hosting environment. This API requires that the calling application be hosted in IIS or WAS.” Fortunately, we can still use Phil Haack’s Route Debugger:

    With the URL of “/Person/23”, it correctly matches my service route for my WCF service.

    WCF REST and MVC are both great and they should be used *together* when appropriate.

    See Also:

    http://codebetter.com/howarddierking/2011/05/09/using-serviceroute-with-existing-mvc-routes/

    http://blogs.microsoft.co.il/blogs/bursteg/archive/2009/01/11/asp-net-mvc-route-constraints.aspx

    Google search key : service routes mvc wcf 

  • 相关阅读:
    php面试专题---2、常量及数据类型考点
    php面试专题---3、运算符考察点
    php面试专题---1、php中变量存储及引用的原理
    html中map标签和area标签的应用(总结)
    nginx中如何设置gzip(总结)
    PHP缓存技术OB系统函数(总结)
    Http协议面试题(总结)
    剑指offer 例题
    程序的模块化的一些见解6-读牛人代码之感
    oracle dblink造成远程数据库session过多
  • 原文地址:https://www.cnblogs.com/malaikuangren/p/2769501.html
Copyright © 2011-2022 走看看