我正在开发一个项目,我们使用存储库模式抽象访问SharePoint存储的数据,如下所示(为简洁起见省略详细信息):
public interface IDocumentRepository { ... }
public class SharePointDocumentRepository: IDocumentRepository
{
public SharePointDocumentRepository(Microsoft.SharePoint.Client.ClientContext clientContext)
{
...
}
}
因此,为了能够在ASP.Net MVC应用程序中使用IDocumentRepository实例,在UnityConfig.cs中,容器配置如下:
...
container.RegisterType<IDocumentRepository, SharePointDocumentRepository>();
...
问题是,在运行时,我得到以下异常:
ClientContext类型有多个长度为1的构造函数。无法使用 消除歧义。
为了解决这个问题,我需要注册如何解析ClientContext。到目前为止,我已经尝试了以下方法,但没有取得任何成功:
所以,我的问题是:有没有办法配置Unity来解析ClientContext,或者我应该回到通过IDocumentRepository接口的属性注入它,每当我得到这个接口的实例?注意:第二种方法将使SharePoint存储库无法在任何其他组件中使用,这些组件无法访问HTTP上下文,因此它不是一个优选的组件。
备注:创建没有DI的存储库实例可以按如下方式完成:
...
[SharePointContextFilter]
public ActionResult Index()
{
SharePointContext spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
using(var clientContext = spContext.CreateUserClientContextForSPHost())
{
var documentRepository = new SharePointDocumentRepository(clientContext);
...
}
...
return View();
}
注意,从“Apps for SharePoint”项目模板创建项目时,会自动生成SharePointContextFilterAttribute
,SharePointContextProvider
和SharePointContext
。
答案 0 :(得分:2)
因此,您的控制器依赖于IDocumentRepository
,但是需要根据某些上下文创建这种依赖关系,这些上下文只能从它自己的控制器操作中获取。正确的吗?
如果是这种情况,那么您需要使用Factory。
在您的情况下,您的工厂应该看起来像这样:
public interface IDocumentRepositoryFactory
{
IDocumentRepository Create(Context context);
}
public class SharePointDocumentRepositoryFactory : IDocumentRepositoryFactory
{
public IDocumentRepository Create(Context context)
{
//Create the repository
SharePointContext spContext = SharePointContextProvider.Current.GetSharePointContext(....);
using(var clientContext = spContext.CreateUserClientContextForSPHost())
{
return new SharePointDocumentRepository(clientContext);
}
}
}
请注意,我在这里使用Context
作为Create
方法的输入。您应该使用控制器中需要的任何上下文来替换它,以便能够构建存储库(如果有的话)。
现在,更改控制器的构造函数以接受构造函数中的IDocumentRepositoryFactory
并将其存储在字段中。
别忘了像这样注册工厂:
container.RegisterType<IDocumentRepositoryFactory, SharePointDocumentRepositoryFactory>();
然后在您的操作中,您可以使用factory来创建这样的存储库:
var repository = m_DocumentRepositoryFactory.Create(....);
其中m_DocumentRepositoryFactory
是用于在构造函数中存储工厂依赖项的字段的名称。
<强>更新强>
由于ClientContext
类是一次性的,因此在我们处理SharePointDocumentRepository
之后返回ClientContext
没有意义。
我建议您使用隔离工厂。像这样:
public interface IDocumentRepositoryIsolationFactory
{
void CreateAndUse(Context context, Action<IDocumentRepository> action);
}
public class SharePointDocumentRepositoryIsolationFactory : IDocumentRepositoryIsolationFactory
{
public void CreateAndUse(Context context, Action<IDocumentRepository> action)
{
//Create the repository
SharePointContext spContext = SharePointContextProvider.Current.GetSharePointContext(....);
using(var clientContext = spContext.CreateUserClientContextForSPHost())
{
var repository = SharePointDocumentRepository(clientContext);
action(repository);
}
}
}
在你的行动中使用它:
m_IsolationFactory.CreateAndUse(... , (repository) =>
{
//repository is a IDocumentRepository, use it here
});
答案 1 :(得分:0)
您可以将ClientContext的实例传递给构造函数:
var clientContext = new ClientContext();
container.RegisterInstance<ClientContext>("myContext", clientContext);
container.RegisterType<IDocumentRepository, SharePointDocumentRepository>(new InjectionConstructor(container.Resolve<ClientContext>("myContext")));