C# 使用相同的HttpClient从MVC控制器调用Web API
我有一个MVC5项目,我需要从MVC控制器调用WebAPI方法。Web API使用基于令牌的身份验证,因此我必须为每个调用传递令牌。我使用下面的代码在HTTP头中传递令牌:C# 使用相同的HttpClient从MVC控制器调用Web API,c#,asp.net-mvc,asp.net-web-api,asp.net-mvc-5,C#,Asp.net Mvc,Asp.net Web Api,Asp.net Mvc 5,我有一个MVC5项目,我需要从MVC控制器调用WebAPI方法。Web API使用基于令牌的身份验证,因此我必须为每个调用传递令牌。我使用下面的代码在HTTP头中传递令牌: HttpClient httpClient = new HttpClient(); string baseUrl = "http://localhost:60477/"; dynamic token = Session["token"]; if (token.AccessToken != null) { httpCl
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
和头,添加在一个位置,而不是在每个操作方法中添加头
在MVC应用程序中,我可以将HttpClient
headers注册代码放在哪里,这样所有控制器都可以使用它?这意味着我不想重复代码,比如在每个操作方法中添加令牌。我该怎么做
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
}
您可以尝试在控制器中使用操作筛选器。尝试添加类似以下内容的覆盖-
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);
}
因此,HttpClient对象以及baseUrl的分配在OnActionExecuting中建立。此代码将在重构的控制器中返回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) 为什么不尽快在全局中移动代码或创建自定义Atribute 这里有一个很好的链接:
您可以尝试创建一个小的帮助器类来创建
httpclient
对象。差不多
public class HttpClientHelper
{
public static HttpClient GetHttpClient()
{
var MyHttpClient = new HttpClient();
dynamic _token = HttpContext.Current.Session["token"];
if (_token == null) throw new ArgumentNullException(nameof(_token));
MyHttpClient.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", _token.AccessToken));
return MyHttpClient;
}
}
然后在控制器中调用它作为
public ActionResult getuser(UserModel user)
{
var httpClient = HttpClientHelper.GetHttpClient();
HttpResponseMessage response = httpClient.GetAsync(baseUrl + "api/Admin/GetStates").Result;
if (response.IsSuccessStatusCode)
{
string stateInfo = response.Content.ReadAsStringAsync().Result;
}
}
最好坚持单一责任原则,并提取与It自己类中的另一个服务的交互,例如
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注入控制器中,并调用其方法。如果您不使用注入(我建议您这样做),您可以在控制器的构造函数中创建一个新实例。谢谢。如何在global.asax文件中放置httpclient代码?请参阅我文章的编辑部分。此外,Ilya Chernomordik建议的注入服务和Danny建议的使用助手方法一样理想。我的建议可能不是最好的,但如果你想尝试一下行动过滤器,那就试试吧。添加到方法中的HttpClient参数可以重构为服务对象,以便将OnActionExecuting override方法中的代码注入到服务对象中。希望有帮助!
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
}
}