8

我正在使用 Ninject 框架构建一个 MVC3 应用程序。我有一个初始化耗时的服务,最后这个服务将有一个包含用户特定信息的对象,然后只要用户会话处于活动状态,我就需要重新使用该服务,这样我可以避免一次又一次地初始化那个服务

所以我的问题是

当我使用 Ninject 绑定服务时,我应该选择什么样的范围,Ninject 中没有每个范围的会话,那么实现需求的最佳方法是什么?还是我走错了方向?

我为我的一项服务创建了一个自定义提供程序,它将根据从当前 Controller.User.Identity.Name 获取的用户名详细信息创建服务。下面的代码将不起作用,因为缺少 userName 局部变量,如何通过 Ninject 将用户名值传递给我的自定义提供程序,以便我可以从 IContext 中获取它?

public class TfsConnectionManagerProvider : Provider<TfsConnectionManager>
    {
        protected override TfsConnectionManager CreateInstance(IContext context)
        {
            Uri serverUri = new Uri(ConfigurationHelper.TfsServerUrl);
            // Connect to the server without impersonation
            using (TfsTeamProjectCollection baseUserConnection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(serverUri))
            {
                // Get the identity management service
                IIdentityManagementService ims = baseUserConnection.GetService<IIdentityManagementService>();

                // Get the identity to impersonate
                TeamFoundationIdentity identity = ims.ReadIdentity
                (
                    IdentitySearchFactor.AccountName,
                    userName,  //NOTE: How can I get user name value from IContext???
                    MembershipQuery.None,
                    ReadIdentityOptions.None
                );

                // Connect using the impersonated identity
                using (TfsTeamProjectCollection impersonatedConnection = new TfsTeamProjectCollection(serverUri, identity.Descriptor))
                {
                    WorkItemStore store = impersonatedConnection.GetService<WorkItemStore>();

                    return new TfsConnectionManager
                    {
                        Store = store
                    };
                }
            }
        }
    }
4

3 回答 3

7

Ninject 有意不提供会话范围,因为在几乎所有情况下,将服务置于会话状态都是错误的。你应该非常小心地使用会话状态,因为它带来了很多缺点。

首先尝试拥有一个无状态的应用程序。

如果有充分的理由将数据置于会话范围内,则将该数据(而不是服务)放入会话状态并使用处于单例、瞬态或请求范围内的服务进行处理(数据和功能分离)。

于 2012-05-04T11:04:40.103 回答
2

我原来使用自定义提供程序来创建实例,并在自定义提供程序中检查它是否存在于会话中。

绑定如下

Bind<IRepository>().ToProvider(new TfsRepositoryProvider());

自定义提供程序如下

public class TfsRepositoryProvider : Provider<TfsRepository>
    {
        private const string SesTfsRepository = "SES_TFS_REPOSITORY";

        protected override TfsRepository CreateInstance(IContext context)
        {
            // Retrieve services from kernel
            HttpContextBase httpContext = context.Kernel.Get<HttpContextBase>();

            if (httpContext == null || httpContext.Session == null)
            {
                throw new Exception("No bind service found in Kernel for HttpContextBase");
            }

            return (httpContext.Session[SesTfsRepository] ?? (
                    httpContext.Session[SesTfsRepository] = new TfsRepository(context.Kernel.Get<IWorkItemStoreWrapper>()))
                ) as TfsRepository;
        }
    }
于 2012-05-09T15:44:12.930 回答
0

好的,您可以在应用程序中缓存/存储用户信息,如果您没有(最近的)用户信息,则仅调用外部服务。在您的用户信息检索“层”中,您只需对这两种可能性进行编程。

在哪里缓存,完全取决于您。例如,您可以将此信息存储在本地数据库中。

显然我理解错了,我很抱歉(在我原来的答案下面)。

例如,您可以使用(例如)保存服务的静态成员(例如)的(抽象)工厂,以便重用它。

尽管取决于您的服务,这可能会产生一些不必要的副作用(我曾经使用 Data Services 做过一次,在 ASP.NET MVC3 应用程序中,由于发生了一些魔法,我的数据上下文有点搞砸了)。我只想说:小心并好好测试它。

于 2012-05-04T08:24:54.780 回答