第一步:在webAPI中安裝 Autofac.WebApi2 。
不要錯誤的安裝Autofac.Mvc5,也不要錯誤的安裝Autofac.WebApi,因爲Autofac.WebApi是給webapi1的,否則會報錯:重寫成員“Autofac.Integration.WebApi.AutofacWebApiDependencyResolver.BeginScope()”時違反了繼承安全
第二步:在App_Start中創建一個類 :取名AutoFacConfig
第三步:引入 using Autofac; using Autofac.Integration.WebApi;
namespace WebApi.App_Start
{
public class AutoFacConfig
{
public static void InitAutoFac()
{
//得到你的HttpConfiguration.
var configuration = GlobalConfiguration.Configuration;
var builder = new ContainerBuilder();
//註冊控制器
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
//可選:註冊Autofac過濾器提供商.
builder.RegisterWebApiFilterProvider(configuration);
//builder.RegisterType(typeof(MyAuthenticationAttribute)).PropertiesAutowired(); //單獨註冊我們的MyAuthenticationAttribute過濾器
var webapiAssembly = Assembly.Load("WebApi");
//註冊webapi項目中現實了IAuthorizationFilter接口或者實現了IActionFilter接口的非抽象過濾器類
builder.RegisterAssemblyTypes(webapiAssembly).Where(r => !r.IsAbstract &&
(typeof(IAuthorizationFilter).IsAssignableFrom(r)) || typeof(IActionFilter).IsAssignableFrom(r)).PropertiesAutowired();
//對Repositorys這個程序集實現了IBaseRepository接口的非抽象類進行註冊
var repository = Assembly.Load("Repositorys");
builder.RegisterAssemblyTypes(repository).Where(r => !r.IsAbstract).AsImplementedInterfaces().SingleInstance()
.PropertiesAutowired();
IContainer container = builder.Build();
//將依賴關係解析器設置爲Autofac。
var resolver = new AutofacWebApiDependencyResolver(container);
configuration.DependencyResolver = resolver;
}
}
}
第四步:在Global.asax中引用執行。
namespace WebApi
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AutoFacConfig.InitAutoFac();//調用InitAutoFac()方法執行
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
在過濾器中使用屬性注入(特別注意過濾器的註冊,過濾器對象最好不要直接new,而是去IOC容器中拿,否則不能直接在過濾器中使用屬性注入)
例如:我創建了一個身份驗證過濾器,如果過濾器中使用了屬性依賴注入,那麼註冊這個過濾器的時候需要從IOC容器中去拿這個過濾器類對象的實例,不能直接new
namespace WebApi
{
public class MyAuthenticationAttribute : IAuthorizationFilter//也可以直接繼承AuthorizationFilterAttribute
{
public IAppInfosRepository app { get; set; }
public bool AllowMultiple => true;
public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
//獲得報文頭中的AppKey和Sign (我們與客戶端約定,在向服務端發起請求的時候,將AppKey和Sign放到請求報文頭中)
IEnumerable<string> appKeys;
if (!actionContext.Request.Headers.TryGetValues("AppKey", out appKeys)) //從請求報文頭中獲取AppKey
{
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized) { Content = new StringContent("報文頭中的AppKey爲空") };
}
}
IEnumerable<string> signs;
if (!actionContext.Request.Headers.TryGetValues("Sign", out signs)) //從請求報文頭中獲取Sign
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized) { Content = new StringContent("報文頭中的Sign爲空") };
}
string appKey = appKeys.First();
string sign = signs.First();
var appInfo = await app.GetByAppKeyAsync(appKey);//從數據庫獲取appinfo這條數據(獲取AppKey,AppSecret信息)
if (appInfo == null)
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized) { Content = new StringContent("不存在的AppKey") };
}
if (appInfo.IsEnable == "true")
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden) { Content = new StringContent("AppKey已經被封禁") };
}
string requestDataStr = ""; //請求參數字符串
List<KeyValuePair<string, string>> requestDataList = new List<KeyValuePair<string, string>>();//請求參數鍵值對
if (actionContext.Request.Method == HttpMethod.Post) //如果是Post請求
{
//獲取Post請求數據
requestDataStr = GetRequestValues(actionContext);
if (requestDataStr.Length > 0)
{
string[] requestParamsKv = requestDataStr.Split('&');
foreach (var item in requestParamsKv)
{
string[] pkv = item.Split('=');
requestDataList.Add(new KeyValuePair<string, string>(pkv[0], pkv[1]));
}
//requestDataList就是按照key(參數的名字)進行排序的請求參數集合
requestDataList = requestDataList.OrderBy(kv => kv.Key).ToList();
var segments = requestDataList.Select(kv => kv.Key + "=" + kv.Value);//拼接key=value的數組
requestDataStr = string.Join("&", segments);//用&符號拼接起來
}
}
if (actionContext.Request.Method == HttpMethod.Get) //如果是Get請求
{
//requestDataList就是按照key(參數的名字)進行排序的請求參數集合
requestDataList = actionContext.Request.GetQueryNameValuePairs().OrderBy(kv => kv.Key).ToList();
var segments = requestDataList.Select(kv => kv.Key + "=" + kv.Value);//拼接key=value的數組
requestDataStr = string.Join("&", segments);//用&符號拼接起來
}
//計算Sign (即:計算requestDataStr+AppSecret的md5值)
string computedSign = MD5Helper.ComputeMd5(requestDataStr + appInfo.AppSecret);
//用戶傳進來md5值和計算出來的比對一下,就知道數據是否有被篡改過
if (sign.Equals(computedSign, StringComparison.CurrentCultureIgnoreCase))
{
return await continuation();
}
else
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized) { Content = new StringContent("sign驗證失敗") };
}
}
/// <summary>
/// 獲取Post請求的請求參數內容
/// 參考資料:https://www.cnblogs.com/hnsongbiao/p/7039666.html
/// </summary>
/// <param name="actionContext"></param>
/// <returns></returns>
public string GetRequestValues(HttpActionContext actionContext)
{
Stream stream = actionContext.Request.Content.ReadAsStreamAsync().Result;
Encoding encoding = Encoding.UTF8;
/*
這個StreamReader不能關閉,也不能dispose, 關了就傻逼了
因爲你關掉後,後面的管道 或攔截器就沒辦法讀取了
所有這裏不要用using
using (StreamReader reader = new StreamReader(stream, System.Text.Encoding.UTF8))
{
result = reader.ReadToEnd().ToString();
}
*/
var reader = new StreamReader(stream, encoding);
string result = reader.ReadToEnd();
/*
這裏也要注意: stream.Position = 0;
當你讀取完之後必須把stream的位置設爲開始
因爲request和response讀取完以後Position到最後一個位置,交給下一個方法處理的時候就會讀不到內容了。
*/
stream.Position = 0;
return result;
}
}
}
在WebApiConfig.cs類中註冊這個過濾器 (統一註冊過濾器)
namespace WebApi
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 配置和服務
// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//從Autofac的IOC容器中拿到MyAuthenticationAttribute過濾器的類對象
//MyAuthenticationAttribute authorFilter = (MyAuthenticationAttribute)GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(MyAuthenticationAttribute));
//config.Filters.Add(authorFilter); //註冊過濾器
//注意:如果想在過濾器中使用屬性注入,則註冊這個過濾器的時候,這個過濾器的對象必須要用IOC容器過得到
//不能直接new 例如:不能直接config.Filters.Add(new MyAuthenticationAttribute())
//因爲一個對象必須是由IOC容器創建出來的,IOC容器纔會自動幫我們注入
#region 統一註冊過濾器
var webapiAss = Assembly.Load("WebApi");
//從webapiAss中拿到所有實現了IAuthorizationFilter接口,或者實現了IActionFilter接口的非抽象過濾器類
var filters = webapiAss.GetTypes().Where(r => !r.IsAbstract && (typeof(IAuthorizationFilter).IsAssignableFrom(r) || typeof(IActionFilter).IsAssignableFrom(r)));
foreach (var item in filters)
{
//從IOC容器中拿到過濾器類對象(因爲過濾器都是實現了IFilter接口的,所有這裏以IFilter接口來接收)
IFilter filter = (IFilter)GlobalConfiguration.Configuration.DependencyResolver.GetService(item);
config.Filters.Add(filter); //註冊過濾器
}
#endregion
}
}
}