我一直在关注Adam Freeman撰写的Pro ASP.NET MVC5书籍,虽然它对于揭示MVC和DI的基础知识非常棒,但是它在应用这些内容方面缺乏细节。学习现实世界的例子。
我想返回文章的视图,并显示该文章的所有评论。使用网络表单这很简单,但我想使用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();
以上几行意味着我现在依赖于一个接口和一个具体的存储库。
控制器如下:
public class ArticleController : Controller
{
private IArticleRepository repository;
public ArticleController(IArticleRepository articleRepository)
{
repository = articleRepository;
}
public PartialViewResult SnippetView(int id)
{
return PartialView(repository.GetByID(id));
}
}
我没有看到添加CommentRepository的方法 - 除非我添加一个Property Injection,它看起来像一个bodge,因为我必须为父类的所有子对象执行此操作。一些子对象也有子对象 - 在这种情况下,Comments有一个Member对象:
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();
}
}
}
评论服务界面和类如下:
评论服务界面:
public interface ICommentService
{
IEnumerable<Comment> Comments { get; }
}
评论服务类: 公共类CommentService:ICommentService { private 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; d out无参数,代码编译并运行,这很好,除了它感觉有点像一个bodge,这使得代码不易测试。
答案 0 :(得分:1)
您选择的IoC容器将解析组件。
你是正确的,因为你不想要属性注入,也不想直接实例化对象(如你的例子)。相反,我会提供一个CommentService,由您的文章类的Dependency Resolver解决。
下面我定义一个简单的界面。接口的实现很重要,因为我还使用依赖项解析器来解析存储库。
public interface ICommentService
{
IEnumerable<Comment> Comments {get;set;}
}
public class CommentService : ICommentService
{
//Using the repository pattern - I assume the comments come from a Database somewhere
private IRepository _repository;
public CommentService(IRepository repository)
{
_repository = repository;
}
IEnumerable<Comments>
{
get
{
return _repository.Comments().ToList();
}
set
{
_repository.Comments.AddRange(val);
_repository.SaveChanges();
}
}
public class Article
{
private ICommentService _commentService;
public Article (ICommentService commentService)
{
_commentService = commentService;
}
//[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; }
[NotMapped]
public IEnumerable<Comment> Comments
{
get
{
//This is all you need
return _commentService.Comments;
}
}
}