在ASP.net Session_Start方法中的依赖注入

本文关键字:依赖 注入 方法 Start ASP net Session | 更新日期: 2023-09-27 18:15:22

我正在学习依赖注入并第一次使用autoface。我按照几个autofacc示例中提到的方式构建了容器(见下文),并从application_start

调用
public class ContainerConfig
{
    public static void RegisterContainer() 
    {
        //Create a new ContainerBuilder
        var builder = new ContainerBuilder();
        // Register all the controllers using the assembly object
        builder.RegisterControllers(Assembly.GetExecutingAssembly());
        //Registering default convention -- IExample and Example
        builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
            .Where(t => t.Name.Single(i => i.Name == "I" + t.Name))
            .AsImplementedInterfaces();
        //Build the container
        var container = builder.Build();
        //Set the default resolver to use Autofac
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 
    }
}

我创建了UserService在我的核心项目IUserService。它有一些方法可以使dbcall从表中获取用户信息。在我的UI项目中,我有一个名为UserProvider的类,我正在试图注入UserService。

public class UserProvider
{
    private readonly IUserService _userService;
    public UserProvider(IUserService userService) 
    {
        _userService = userService;
    }
    public void LoadCurrentUser()
    {
        Users FoundUser = _userService.ImportOrGetUser();
        if (FoundUser != null)
        {
            //add it to session
            CurrentUser = FoundUser;
        }
    }
}

这个UserProvider,我正在使用我的session_start

void Session_OnStart()
{
     UserProvider OUsrPrv = new UserProvider(new UserService());
     OUsrPrv.LoadCurrentUser();
}

在上面的代码中,如果我传递'new UserService()',我的理解是我手动注入UserService。我看不出自动识别在这里有什么用。在谷歌的所有例子都在谈论依赖注入在MVCController或WebApiController,而不是在一个单独的类(UserProvider)像我做的。

谁能给点光照吗?我做错了吗?

在ASP.net Session_Start方法中的依赖注入

为了正确使用依赖注入,你不应该自己创建实例,底层框架应该为你提供实例。

但是ASP.net调用Session_OnStart没有任何依赖注入。在这种情况下,您可以使用DependencyResolver.Current静态属性来解析所请求的服务。

void Session_OnStart()
{
    UserProvider userProvider = DependencyResolver.Current.GetService<UserProvider>();
    userProvider.LoadCurrentUser(); 
}

System.Web.HttpApplication中的事件模型是ASP的一部分。NET,而不是MVC。它不是为依赖注入设计的。

Cyril建议的答案是使用服务定位器来获取对服务的引用。这远非理想状态,因为您在代码中使用了对服务定位器的依赖。

以mvc为中心的实现横切关注点的方法(比如将用户数据加载到会话状态)是使用全局注册的过滤器。您可以实现IAuthorizationFilterIActionFilter来获得所需的效果。在这种情况下,使用IActionFilter是有意义的,因为您想要等到您确定有一个授权用户才调用它。

注意:虽然这回答了你的具体问题,但最好不要在MVC中使用会话状态。另一种选择是使用ASP。使用声明的. NET标识来存储用户配置文件数据,而不是使用会话。

using System;
using System.Web.Mvc;
using System.Security.Principal;
public class GetUserActionFilter : IActionFilter
{
    private readonly IUserRepository userRepository;
    public GetUserActionFilter(IUserRepository userRepository)
    {
        if (userRepository == null)
            throw new ArgumentNullException("userRepository");
        this.userRepository = userRepository;
    }
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // Do nothing - this occurs after the action method has run
    }
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        IPrincipal user = filterContext.HttpContext.User;
        if (user == null)
        {
            return;
        }
        IIdentity identity = user.Identity;
        if (identity == null)
        {
            return;
        }
        // Make sure we have a valid identity and it is logged in.
        if (identity.IsAuthenticated)
        {
            string key = "__CurrentUserData";
            var userData = filterContext.HttpContext.Session[key];
            if (userData == null)
            {
                // User data doesn't exist in session, so load it
                userData = userRepository.GetUserData(identity.Name);
                // Add it to session state
                filterContext.HttpContext.Session[key] = userData;
            }
        }
    }
}

现在,要全局添加过滤器,需要:

  1. 在Autofac中注册过滤器及其依赖项
  2. 将容器传递给静态RegisterGlobalFilters方法

注册过滤器

使用命名实例将其与其他潜在的IActionFilter实例区分开来。

builder.RegisterType<GetUserActionFilter>()
       .Named<IActionFilter>("getUserActionFilter");

传递容器

FilterConfig.cs

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters, IContainer container)
    {
        filters.Add(container.ResolveNamed<IActionFilter>("getUserActionFilter"));
        filters.Add(new HandleErrorAttribute());
    }
}

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    // This method serves as the composition root
    // for the project.
    protected void Application_Start()
    {
        // Register Autofac DI
        IContainer container = ContainerConfig.RegisterContainer();
        AreaRegistration.RegisterAllAreas();
        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters, container);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }
}

ContainerConfig.cs

public class ContainerConfig
{
    public static IContainer RegisterContainer() 
    {
        //Create a new ContainerBuilder
        var builder = new ContainerBuilder();
        // Register all the controllers using the assembly object
        builder.RegisterControllers(Assembly.GetExecutingAssembly());
        //Registering default convention -- IExample and Example
        builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
              .Where(t => t.Name.Single(i => i.Name == "I" + t.Name))
              .AsImplementedInterfaces();
        // Register our filter
        builder.RegisterType<GetUserActionFilter>()
           .Named<IActionFilter>("getUserActionFilter");
        //Build the container
        var container = builder.Build();
        //Set the default resolver to use Autofac
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 
        // Return the container to our composition root.
        return container;
    }
}

请注意,我在这里只使用了一个存储库服务,因为HttpContext已经通过动作过滤器直接可用,这里需要额外的逻辑,因为我们不确定它是否存在于会话状态中,或者是否有一个用户要查找,所以我们的过滤器除了加载会话状态外还会进行这些检查。