【发布时间】:2016-07-05 12:25:34
【问题描述】:
我一直在关注 Adam Freeman 撰写的 Pro ASP.NET MVC5 书籍,虽然它对于揭示 MVC 和 DI 的基础知识非常棒,但在将所学知识应用于现实世界的示例时却有点缺乏细节。
我想返回一篇文章的视图,并显示该文章的所有 cmets。使用网络表单这很简单,但是我想使用 MVC 和 DI,但我不确定如何继续。
我有文章类:
public class Article
{
//[DataMember]
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
//[DataMember]
[Required(ErrorMessage = "Please enter a headline")]
[StringLength(100, ErrorMessage = "Headline cannot be longer than 100 characters.")]
public virtual string Headline { get; set; }
[...]
//TO DO: Find a way to use DI for this
//[NotMapped]
private IEnumerable<Comment> comments;
[NotMapped]
public IEnumerable<Comment> Comments
{
get
{
if (null == comments)
{
ICommentRepository cRepository = new CommentRepository();
comments = cRepository.Comments.Where(c => c.ArticleID == this.ID).ToList();
}
return comments;
}
}
}
我遇到的问题是线条:
ICommentRepository cRepository = new CommentRepository();
comments = cRepository.Comments.Where(c => c.ArticleID == this.ID).ToList();
以上几行意味着我现在依赖于一个接口和一个具体的存储库。
Controller如下:
public class ArticleController : Controller
{
private IArticleRepository repository;
public ArticleController(IArticleRepository articleRepository)
{
repository = articleRepository;
}
public PartialViewResult SnippetView(int id)
{
return PartialView(repository.GetByID(id));
}
}
我看不到向其中添加 CommentRepository 的方法 - 除非我添加一个属性注入,这似乎是一个障碍,因为我必须为父类的所有子对象执行此操作。一些子对象也有子对象——在这种情况下,评论有一个成员对象:
public PartialViewResult SnippetView(int id)
{
Article a = repository.GetByID(id);
a.CommentReposiory = ICommentRepository;
return PartialView(repository.GetByID(id));
}
我已根据@JDBennett 提供的回复更新了课程
文章类为评论服务添加了一个参数化构造函数:
public class Article
{
private ICommentService _commentService;
//public Article()
//{
// IKernel ninjectKernel = new StandardKernel();
// ninjectKernel.Bind<ICommentService>().To<CommentService>();
// ninjectKernel.Bind<ICommentRepository>().To<CommentRepository>();
// _commentService = ninjectKernel.Get<ICommentService>();
//}
public Article(ICommentService commentService)
{
_commentService = commentService;
}
//[DataMember]
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[...]
[NotMapped]
public IEnumerable<Comment> Comments
{
get
{
//return _commentService.Comments.ToList();
return _commentService.Comments.Where(c => c.ID == this.ID).ToList();
}
}
}
注释Service接口和类如下:
评论服务接口:
public interface ICommentService
{
IEnumerable<Comment> Comments { get; }
}
评论服务类: 公共类评论服务:ICommentService { 私有 ICommentRepository cRepository;
public CommentService(ICommentRepository repo)
{
cRepository = repo;
}
public IEnumerable<Comment> Comments
{
get
{
return cRepository.Comments.ToList();
}
/*set not yet implemented*/
}
}
ninject 解析器代码是:
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernelParam)
{
kernel = kernelParam;
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
//put bindings here
//comment service
kernel.Bind<ICommentService>().To<CommentService>();
//Community db
kernel.Bind<IBlogRepository>().To<BlogRepository>();
kernel.Bind<ICommentRepository>().To<CommentRepository>();
//news db
kernel.Bind<IArticleRepository>().To<ArticleRepository>();
kernel.Bind<IMemberRepository>().To<MemberRepository>();
//registration db
kernel.Bind<IEventRepository>().To<EventRepository>();
kernel.Bind<IRegistrationRepository>().To<RegistrationRepository>();
}
}
ninjectwebcommon 文件,位于 app_start 文件夹中:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Nordics.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(Nordics.App_Start.NinjectWebCommon), "Stop")]
namespace Nordics.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(new Nordics.Infrastructure.NinjectDependencyResolver(kernel));
}
}
}
代码可以编译,但是当我尝试运行代码时出现错误:
System.Reflection.TargetInvocationException was unhandled by user code.
Message=Exception has been thrown by the target of an invocation.
[...]
InnerException: System.InvalidOperationException
Message=The class 'Domain.Entities.Article' has no parameterless constructor.
如果我要更新 Article 类以删除参数化构造函数,然后添加 remm'd 无参数构造函数,代码编译并运行,这很好,只是感觉有点麻烦,这使得代码的可测试性较低。
【问题讨论】:
-
您的
Comments属性应该有一个简单的{ get; set; },并且您将IArticleRepository和ICommentRepository都注入到控制器中。但是无论如何您都应该使用视图模型,而不是具有[NotMapped]属性的数据模型 -
你真的需要注入一个 ICommentRepository 吗?如果它们在同一个 DbContext 中,为什么不使用导航属性将评论映射到文章。就像斯蒂芬说的那样,将您的视图模型与您的 ef 模型分开。
-
@Fran Comments 表位于 Articles 表的单独 dbContext 中。
-
Article 类 public IEnumerable
中的这条语句在不同的上下文中如何工作 -
嗨@Fran,我不确定我是否理解这个问题,但是:我在 web.config 文件中有 2 个连接字符串值,每个数据库/dbcontext 一个。
标签: asp.net-mvc dependency-injection