n8w*_*wrl 5 asp.net-mvc-routing asp.net-mvc-4 asp.net-web-api
我们有一个长期运行的ASP.NET Web表单应用程序,它诞生于.NET 1.1/IIS6时代.我们现在使用的是.NET4.5/IIS7,但我们对MVC一无所知.
我们为客户提供目录,并为他们提供可以使用的URL:
www.ourhost.com/customername
Run Code Online (Sandbox Code Playgroud)
使用我们开发的自定义IHttpModule,我们从URL中提取"customername"以在数据库中查找客户.然后,该客户的ID将存储在页面的上下文*中,并由网站上的几乎所有页面使用,以便为该客户自定义内容.完成此过程后,上述URL将被重写并处理为
www.ourhost.com/index.aspx
Run Code Online (Sandbox Code Playgroud)
index.aspx可以通过其上下文访问客户的ID,它可以做到这一点.
这很好用,我们用它支持数千名客户.重写逻辑相当复杂,因为它验证了客户帐户,如果客户无效,则重定向到"哦"页面,如果客户没有付款,则重定向到"查找经销商"页面等.
现在我想构建一些Web API控制器,MVC风格的重写令我担心.我看到很多例子,其中重写恰好使URL像这样工作:
www.ourhost.com/api/{controller}
Run Code Online (Sandbox Code Playgroud)
但我仍然需要在客户的环境中发生这些web api'调用'.我们的页面使用JSON/AJAX异步调用变得越来越复杂,但在回答这些调用时,我仍然需要客户上下文.我想要的URL是
www.ourhost.com/customername/api/{controller}
Run Code Online (Sandbox Code Playgroud)
但我很困惑如何配置路由来做到这一点,并让它与我们的IHttpModule很好地配合.
这甚至可能吗?
*更新:当我说"存储在页面上下文中"时,我指的是与每个Web请求相关联的HttpContext,其中包含一个字典,我可以在其中存储一些页面/请求特定的数据.
小智 2
我可以看到您的问题的答案分为两部分。
跨多个请求维护用户信息 通常,MVC API 应用程序是无状态的,也就是说,您不会在请求之间保留当前用户的会话状态。这就是我在编写 RESTFul API 时学到或多次宣讲的内容。
也就是说,您可以通过将以下内容添加到 global.asax.cs 中来启用 MVC Web API 中的会话状态
protected void Application_PostAuthorizeRequest()
{
// To enable session state in the WebAPI.
System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
}
Run Code Online (Sandbox Code Playgroud)
在请求中授权客户 正如您在请求 URL 中所示,您可以添加客户名称,然后捕获该名称并将其传递到当前 http 模块调用以根据请求进行授权的同一例程。您可以使用 MVC 过滤器来完成此操作。
首先执行类似的 URL 模式来捕获 WebApiConfig.cs 中的客户名称,如下所示;
config.Routes.MapHttpRoute(
name: "WithCustomerApi",
routeTemplate: "api/{customername}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Run Code Online (Sandbox Code Playgroud)
然后将 ActionFilter 添加到您的 API 控制器,该控制器处理每个请求、检查当前会话信息,并在需要时调用您的授权/客户查找代码,然后保存到会话状态以供以后使用。或者,如果客户没有好的信息可以发送到新的 MVC 路线
所以你将添加一个类似这样的属性;
[WebApiAuthentication]
public class BaseApiController : ApiController
{
}
Run Code Online (Sandbox Code Playgroud)
然后创建一个可能看起来像这样的操作过滤器(注意我还没有测试过这个,只是为了了解如何做的模式)。
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您创建一个新的 MVC 5 Web 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" };
}
}
Run Code Online (Sandbox Code Playgroud)
正如我所说,我将其作为一种可能的解决方案提供,关于在 API 中存储会话和授权存在宗教争论,但这些不是问题。希望有帮助,史蒂夫
| 归档时间: |
|
| 查看次数: |
1884 次 |
| 最近记录: |