ASP.NET5 MVC6 利用Middleware 创建可访问HttpContext 的业务类工厂。(代替HttpContext.Current)
我们的目标是在后台业务处理类中,能够很容易的取得用户信息或者其它HTTP请求相关的信息。
所以,首先我们需要一个存储这些信息的类:
1 public class RequestData 2 { 3 public string UserName { get; set; } 4 5 public int UserId { get; set; } 6 7 public UriBuilder Url { get; set; } 8 }
这个请求信息类,是我们业务工厂类的一个属性:
1 public class DataControllerFactory 2 { 3 public RequestData RequestData { get; set; } = new RequestData(); 4 5 public T Create<T>() where T : BaseBusiness 6 { 7 T dc = Activator.CreateInstance<T>(); 8 dc.RequestData = this.RequestData; 9 return dc; 10 } 11 }
这个工厂类里的BaseBusiness就是所有业务处理类的基类:
1 public class BaseBusiness 2 { 3 public RequestData RequestData { get; set; } 4 }
也许基类加上 abstract关键字更好些。 接着创建一个用于测试的业务处理类:
1 public class TestDataController: BaseDataController 2 { 3 }
好吧,它是空的,但是做测试够用了。 后台业务层就是上面这些类了。 下面是前台MVC里利用 DI 和 Middleware 实现RequestData的传递和业务类的创建。
首先创建RequestMiddleware
1 public abstract class AbstractMiddleware 2 { 3 protected RequestDelegate Next { get; set; } 4 5 protected AbstractMiddleware(RequestDelegate next) 6 { 7 this.Next = next; 8 } 9 10 public abstract Task Invoke(HttpContext context); 11 } 12 13 public class RequestMiddleware:AbstractMiddleware 14 { 15 public RequestMiddleware(RequestDelegate next) : base(next) { } 16 17 public async override Task Invoke(HttpContext context) 18 { 19 DataControllerFactory factory = context.RequestServices.GetService(typeof(DataControllerFactory)) as DataControllerFactory; 20 factory.RequestData.UserName = context.User.Identity.Name??"Not Login"; 21 await this.Next.Invoke(context); 22 } 23 }
这里用了个基类 AbstractMiddleware, 不过看来作用不大,它不是必须的。
在Startup类里的 Configure 方法中, 注册这个中间件:
app.UseMiddleware<RequestMiddleware>();
//下面的代码也在Configure方法中,用于开启cookie认证功能,这样可以大大的简化登录代码,便于测试或者集成已有的用户管理系统。
//app.UseIdentity();
app.UseCookieAuthentication(options =>
{
options.AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.CookieHttpOnly = true;
});
顺便在其 ConfigureServices 方法中添加 业务类工厂 的依赖注入类型
services.AddScoped<DataControllerFactory>();
有可能 这行代码 需要在 services.AddMvc(); 的上面, 总之有时顺序很重要, 但我还没有时间仔细测试这些问题。
下面我们就要测试一下我们能不能取得业务类工厂,并且创建出带有登录请求信息的业务类。
有了上面开启cookie认证的代码,我们在Controller中的登录Action便很简单了:
1 //这里用了API形式的测试登录方法
public string Login() 2 { 3 List<Claim> claims = new List<Claim>(); 4 claims.Add(new Claim("Name", "TestName", ClaimValueTypes.String)); 5 claims.Add(new Claim(ClaimTypes.Name, "TestName", ClaimValueTypes.String)); 6 ClaimsIdentity identity = new ClaimsIdentity(claims, "AuthenticationType", "Name", ClaimTypes.Role); 7 ClaimsPrincipal principal = new ClaimsPrincipal(identity); 8 HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal); 9 return "ok"; 10 }
下面是测试 Factory 和 相关登录请求数据的 Action :
1 public IActionResult TestLogin() 2 { 3 var factor = GetService<DataControllerFactory>(); 4 TestDataController tdc = factor.Create<TestDataController>(); 5 ViewBag.UserName = tdc.RequestData.UserName; 6 return View(); 7 }
VIEW层调用登录action和测试action的方法很简单,这里就不再写了。