从mvc控制器调用webapi并使用相同的httpclient

时间:2016-05-12 04:56:53

标签: c# asp.net-mvc asp.net-web-api asp.net-mvc-5

我有MVC5项目,从控制器需要调用webapi方法。 Webapi由基于令牌的身份验证实现。因此我必须为每个调用传递令牌。我使用下面的代码在httpheader中传递令牌。

HttpClient httpClient = new HttpClient();
        string baseUrl = "http://localhost:60477/";
 dynamic token = Session["token"];
            if (token.AccessToken != null)
            {
                httpClient.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", token.AccessToken));
            }

我在我的控制器中有多个动作方法,比如,我想使用单个httpclient,并且需要在一个地方添加标题,而是在每个动作方法中添加标题。我可以将httpclient标题注册码放在mvc应用程序中,以便所有控制器都可以使用。这意味着我不想重复代码,比如在每个动作方法中添加令牌。我怎么能这样做

Public ActionResult Postuser(UserModel user)
{
 //post code
}
Public ActionResult getuser(UserModel user)
{
 HttpResponseMessage response = httpClient.GetAsync(baseUrl + "api/Admin/GetStates").Result;
            if (response.IsSuccessStatusCode)
            {
                string stateInfo = response.Content.ReadAsStringAsync().Result;
    }

}
Public ActionResult PostRoles(RoleModel role)
{
//post roles code
}

3 个答案:

答案 0 :(得分:2)

最好遵守单一责任原则,并在其自己的班级中提取与其他服务的互动,例如

public class ServiceClient : IServiceClient
{
    private HttpClient m_Client;        

    public ServiceClient
    {
         m_Client = new HttpClient();
         // Initialize the client as you need here
    }

    public void CallSomeMethod()
    {
        // Call method on the client
    }
}

然后在控制器中注入IServiceClient并调用它的方法。如果你不使用注入(我建议你这样做),你可以在控制器的构造函数中创建一个新实例。

答案 1 :(得分:1)

您可以尝试在控制器中使用动作过滤器。尝试添加看起来像这样的覆盖 -

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
  // some condition code to target a specific method in the controller
  // Example
  if (filterContext.ActionDescriptor.ActionName == "getuser") // <-- your method
  {
    // put your token based authentication code here
  }

  base.OnActionExecuting(filterContext);
}

OnActionExecuting方法位于控制器范围内,因此您可以为不同的控制器使用不同的逻辑。

如果要在操作方法之后运行代码,还有一个OnActionExecuted方法覆盖。

------编辑--------------

至于放置HttpClient代码段的位置,您可以试试这个 -

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
  HttpClient httpClient = new HttpClient();
  string baseUrl = "http://localhost:60477/";
  dynamic token = Session["token"];

  if (token.AccessToken != null)
  {
    httpClient.DefaultRequestHeaders.Add(
        "Authorization",
        string.Format("Bearer {0}", token.AccessToken)
    );

    httpClient.BaseAddress = new Uri(baseUrl);
  }

  if(filterContext.ActionParameters.ContainsKey("httpClient"))
  {
    filterContext.ActionParameters["httpClient"] = httpClient;
  }
  else
  {
    // error
  }

  base.OnActionExecuting(filterContext);
}

因此,在OnActionExecuting中建立了HttpClient对象以及baseUrl的赋值。此代码将在您重构的控制器中返回ActionResult的任何方法之前运行。如果您想要定位一些而不是所有方法,请参阅上面的OnActionExecuting的第一个示例。

public ActionResult getuser(UserModel user, HttpClient httpClient)
{
  HttpResponseMessage response = httpClient.GetAsync("api/Admin/GetStates").Result;

  if(response.IsSuccessStatusCode)
  {
    string stateInfo = response.Content.ReadAsStringAsync().Result;
  }

  // the rest of your code for getuser..

  return View();
}

现在你的getuser方法有一个额外的参数(HttpClient httpClient)。

答案 2 :(得分:0)

为什么不在Global asax中移动代码或创建自定义属性?

这是一个很好的链接: http://www.diaryofaninja.com/blog/2011/07/24/writing-your-own-custom-aspnet-mvc-authorize-attributes