2013-04-23 93 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在授權宗教論點,但這些都不是問題。 希望有幫助, 史蒂夫