2013-04-23 94 views
5

我们已经得到了出生在.NET 1.1/IIS6天长时间运行ASP.NET web的表单应用程序。我们现在在.NET4.5/IIS7上,但是我们没有对MVC做任何事情。URL重写和Web API

我们提供了一个目录给客户,并给他们,他们可以使用的URL:

www.ourhost.com/customername 

使用IHttpModule的,我们开发我们拉“客户名称”出来的URL找到在数据库中的用户自定义。然后,该客户的ID存储在页面的上下文中*,并被网站上的几乎所有页面用于为该客户定制内容。在这个过程之后,上面的URL会被重写,并处理为

www.ourhost.com/index.aspx 

具有通过它的上下文获得了客户的ID的Index.aspx,它可以做它的事。

这个伟大的工程,我们支持几千个客户了。重写逻辑相当复杂,因为它验证了客户帐户,如果客户无效,则重定向到'呃哦'页面,如果客户没有支付,则重定向到'找到经销商'页面等。

现在我想构建一些Web API控制器,MVC风格的重写让我担心。我看到很多例子,其中重写发生,使URL的这样的工作:

www.ourhost.com/api/{controller} 

但我仍然需要这些Web API“调用”在客户的情况下发生的。我们的页面使用JSON/AJAX异步调用变得更加复杂,但在回答这些调用时,我仍然需要客户环境。我想URL的是

www.ourhost.com/customername/api/{controller} 

但我难倒如何配置路由要做到这一点,并将它与我们的IHttpModule发挥很好。

这甚至可能吗?

*更新:当我说“存储在页上下文中的”我的意思是与包括字典,我可以存储一些网页/请求特定的数据每个Web请求关联的HttpContext。

+0

当你说“存储在页面的上下文中” - 你是指'Session'对象,还是你直接写入某种'Cookie'?既然你标记了这个'web-api',它就会有点不同。 – 2013-04-24 20:01:19

+0

@Troy:感谢您的评论 - 我已经通过澄清更新了我的问题。 – n8wrl 2013-04-25 12:11:09

+0

明白了 - 您正在使用'HttpContext.Current.User'来跟踪您登录的用户是谁?你如何将它保存到后续调用中,该调用在URL中不包含用户的用户名? – 2013-04-25 16:41:54

回答

2

您可以看到问题的答案有两个部分。

维护跨多个请求 用户信息一般的MVC API应用程序将是无状态的,那是你不保留请求之间的当前用户的会话状态。那么这就是我在编写RESTFul API时已经学会或多次被鼓吹过的东西。

也有人说,你可以通过添加启用MVC的Web API会话状态下你的global.asax.cs

protected void Application_PostAuthorizeRequest() 
    { 
     // To enable session state in the WebAPI. 
     System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); 
    } 

授权客户在申请 当您在显示请求URL可以添加客户名称,然后捕获并将其传递给您当前的http模块调用以根据请求进行授权的相同例程。你可以用MVC过滤器来做到这一点。

首先做一个类似的URL模式捕捉到你的客户在WebApiConfig名。CS,就像这样;

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

然后一个ActionFilter添加到处理每个请求,检查当前的会话信息的API控制器,如果需要调用你的授权/客户查找代码,然后保存到会话状态以备后用。或者,如果没有客户的良好信息可以发送到新的MVC路线

因此,您将添加一个类似于此的属性;

[WebApiAuthentication] 
public class BaseApiController : ApiController 
{ 
} 

然后创建一个动作过滤器可能看起来像这样的(注意我没有测试过这一点,只是做了怎样的模式)。

public class WebApiAuthenticationAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     var routeData = actionContext.ControllerContext.Request.GetRouteData(); 
     var currentContext = HttpContext.Current; 

     if (routeData.Route.RouteTemplate.Contains("customername")) 
     { 
      try 
      { 
       var authenticated = currentContext.Request.IsAuthenticated; 
       if (!authenticated) 
       { 
        var customer = routeData.Values["customername"]; 
        // do something with customer here and then put into session or cache 
        currentContext.Session.Add("CustomerName", customer); 
       } 
      } 
      catch (Exception exception) 
      { 
       var error = exception.Message; 
       // We dont like the request 
       actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest); 
      } 
     } 
     else 
     { 
      // No customer name specified, send bad request, not found, what have you ... you *could* potentially redirect but we are in API so it probably a service request rather than a user 
      actionContext.Response = new HttpResponseMessage(HttpStatusCode.NotFound); 
     } 

    } 
} 

如果您创建一个新的MVC的Web 5 API应用并添加这些额外并把过滤器的默认值控制器上一样,所以你应该能够看到这个运行的可能的解决方案的演示。

如果一切正常,这将回显客户名称。

[WebApiAuthentication] 
public class ValuesController : ApiController 
{ 
    // GET api/values 
    public IEnumerable<string> Get() 
    { 
     var session = HttpContext.Current.Session; 

     if (session != null) 
     { 
      return new string[] {"session is present", "customer is", session["CustomerName"].ToString()}; 
     } 

     return new string[] { "value1", "value2" }; 
    } 

} 

我提供了这样一个可能的解决方案,因为我说的,大概有存储会话和API在授权宗教论点,但这些都不是问题。 希望有帮助, 史蒂夫