BZi*_*ink 34 asp.net-mvc constructor c#-4.0 asp.net-mvc-2
我正在研究ASP.net MVC应用程序,我有一个关于为我的控制器使用构造函数的问题.
我正在使用Entity Framework和linq来实现所有数据事务的实体.我需要为几乎所有的控制器操作访问我的实体模型.当我第一次开始编写应用程序时,我在每个Action方法的开头创建了一个实体对象,执行我需要的任何工作然后返回我的结果.
我意识到我正在为每个动作方法反复创建相同的对象,所以我为Entity对象创建了一个私有成员变量,并开始在每个控制器的构造函数中实例化它.现在每个方法只引用私有成员变量来完成它的工作.
我仍在质疑自己哪种方式是正确的.我想知道A.)哪种方法最合适?B.)在构造函数方法中,这些对象生存了多长时间?C.)构造函数方法是否存在性能/完整性问题?
谢谢
Str*_*ior 30
RCravens有一些很好的见解.我想展示一下如何实施他的建议.
最好从定义数据访问类的接口来实现:
public interface IPostRepository
{
IEnumerable<Post> GetMostRecentPosts(int blogId);
}
Run Code Online (Sandbox Code Playgroud)
然后实现一个数据类.实体框架上下文构建起来很便宜,当你不处理它们时你可能会得到不一致的行为,因此我发现通常最好将你想要的数据提取到内存中,然后处理上下文.
public class PostRepository : IPostRepository
{
public IEnumerable<Post> GetMostRecentPosts(int blogId)
{
// A using statement makes sure the context is disposed quickly.
using(var context = new BlogContext())
{
return context.Posts
.Where(p => p.UserId == userId)
.OrderByDescending(p => p.TimeStamp)
.Take(10)
// ToList ensures the values are in memory before disposing the context
.ToList();
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您的控制器可以接受其中一个存储库作为构造函数参数:
public class BlogController : Controller
{
private IPostRepository _postRepository;
public BlogController(IPostRepository postRepository)
{
_postRepository = postRepository;
}
public ActionResult Index(int blogId)
{
var posts = _postRepository.GetMostRecentPosts(blogId);
var model = new PostsModel { Posts = posts };
if(!posts.Any()) {model.Message = "This blog doesn't have any posts yet";}
return View("Posts", model);
}
}
Run Code Online (Sandbox Code Playgroud)
MVC允许您使用自己的Controller Factory代替默认值,因此您可以指定像Ninject这样的IoC框架决定如何创建控制器.您可以设置注入框架,以便知道当您要求IPostRepository时,它应该创建一个PostRepository对象.
这种方法的一大优点是它使您的控制器可以进行单元测试.例如,如果要确保模型在没有帖子时获取消息,可以使用像Moq这样的模拟框架来设置一个场景,其中您的存储库不返回任何帖子:
var repositoryMock = new Mock<IPostRepository>();
repositoryMock.Setup(r => r.GetMostRecentPosts(1))
.Returns(Enumerable.Empty<Post>());
var controller = new BlogController(repositoryMock.Object);
var result = (ViewResult)controller.Index(1);
Assert.IsFalse(string.IsNullOrEmpty(result.Model.Message));
Run Code Online (Sandbox Code Playgroud)
这样可以轻松测试控制器操作所期望的特定行为,而无需设置数据库或类似的任何特殊行为.像这样的单元测试很容易编写,确定性(它们的通过/失败状态是基于代码,而不是数据库内容),而且速度很快(通常可以在一秒钟内运行其中的一千个).
rcr*_*ens 29
你在问正确的问题.
答:在每个操作方法中创建此依赖项绝对不合适.MVC的一个主要特征是能够分离关注点.通过使用这些依赖项加载控制器,您可以使控制器变厚.这些应该注入控制器.依赖注入(DI)有多种选择.通常,这些类型的对象可以注入构造函数或属性中.我的偏好是构造函数注入.
B.这些对象的生命周期将由垃圾收集器确定.GC不具有确定性.因此,如果您拥有与资源受限服务(数据库连接)连接的对象,那么您可能需要确保关闭自己的连接(而不是依赖于dispose).很多时候,"生命"问题被分成控制反转(IOC)容器.那里有很多.我的偏好是Ninject.
C.实例化成本可能很小.数据库事务成本是您可能希望集中注意力的地方.你可能想要研究一个叫做"工作单元"的概念.实质上,数据库可以处理大于一个保存/更新操作的事务.增加事务大小可以提高数据库性能.
希望能让你开始.
短发
归档时间: |
|
查看次数: |
37802 次 |
最近记录: |