我的 MVC 存储库模式和 StructureMap 的问题 [英] Issues with my MVC repository pattern and StructureMap

查看:22
本文介绍了我的 MVC 存储库模式和 StructureMap 的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 ado.net 实体框架之上创建了一个存储库模式.当我尝试实现 StructureMap 来解耦我的对象时,我不断收到 StackOverflowException(无限循环?).这是模式的样子:

I have a repository pattern i created on top of the ado.net entity framework. When i tried to implement StructureMap to decouple my objects, i kept getting StackOverflowException (infinite loop?). Here is what the pattern looks like:

IEntityRepository where TEntity : 类定义基本的 CRUD 成员

IEntityRepository where TEntity : class Defines basic CRUD members

MyEntityRepository : IEntityRepository实现 CRUD 成员

MyEntityRepository : IEntityRepository Implements CRUD members

IEntityService where TEntity : 类定义为每个成员返回公共类型的 CRUD 成员.

IEntityService where TEntity : class Defines CRUD members which return common types for each member.

MyEntityService : IEntityService使用存储库检索数据并作为结果返回一个通用类型(IList、bool 等)

MyEntityService : IEntityService Uses the repository to retrieve data and return a common type as a result (IList, bool and etc)

问题似乎出在我的服务层.更具体地说是构造函数.

The problem appears to be with my Service layer. More specifically with the constructors.

    public PostService(IValidationDictionary validationDictionary)
        : this(validationDictionary, new PostRepository())
    { }

    public PostService(IValidationDictionary validationDictionary, IEntityRepository<Post> repository)
    {
        _validationDictionary = validationDictionary;
        _repository = repository;
    }

从控制器中,我传递了一个实现 IValidationDictionary 的对象.我显式调用第二个构造函数来初始化存储库.

From the controller, i pass an object that implements IValidationDictionary. And i am explicitly calling the second constructor to initialize the repository.

这是控制器构造函数的样子(第一个创建验证对象的实例):

This is what the controller constructors look like (the first one creates an instance of the validation object):

    public PostController()
    {
        _service = new PostService(new ModelStateWrapper(this.ModelState));
    }

    public PostController(IEntityService<Post> service)
    {
        _service = service;
    }

如果我不传递我的 IValidationDictionary 对象引用,则一切正常,在这种情况下,第一个控制器构造函数将被删除,并且服务对象将只有一个接受存储库接口作为参数的构造函数.

Everything works if i don't pass my IValidationDictionary object reference, in which case the first controller constructor would be removed and the service object would only have one constructor which accepts the repository interface as the parameter.

感谢您对此的任何帮助:) 谢谢.

I appreciate any help with this :) Thanks.

推荐答案

看起来循环引用与服务层依赖于控制器的 ModelState 而控制器依赖于服务层的事实有关.

It looks like the circular reference had to do with the fact that the service layer was dependent on the Controller's ModelState and the Controller dependent on the Service layer.

>

我必须重写我的验证层才能使其正常工作.这是我所做的.

I had to rewrite my validation layer to get this to work. Here is what i did.

定义通用验证器接口,如下所示:

Define generic validator interface like below:

public interface IValidator<TEntity>
{
    ValidationState Validate(TEntity entity);
}

我们希望能够返回一个 ValidationState 实例,它显然定义了验证状态.

We want to be able to return an instance of ValidationState which, obviously, defines the state of validation.

public class ValidationState
{
    private readonly ValidationErrorCollection _errors;

    public ValidationErrorCollection Errors
    {
        get
        {
            return _errors;
        }
    }

    public bool IsValid
    {
        get
        {
            return Errors.Count == 0;
        }
    }

    public ValidationState()
    {
        _errors = new ValidationErrorCollection();
    }
}

请注意,我们还需要定义一个强类型错误集合.该集合将由 ValidationError 对象组成,这些对象包含我们正在验证的实体的属性名称以及与其关联的错误消息.这只是遵循标准的 ModelState 接口.

Notice that we have an strongly typed error collection which we need to define as well. The collection is going to consist of ValidationError objects containing the property name of the entity we're validating and the error message associated with it. This just follows the standard ModelState interface.

public class ValidationErrorCollection : Collection<ValidationError>
{
    public void Add(string property, string message)
    {
        Add(new ValidationError(property, message));
    }
}

这是 ValidationError 的样子:

And here is what the ValidationError looks like:

public class ValidationError
{
    private string _property;
    private string _message;

    public string Property
    {
        get
        {
            return _property;
        }

        private set
        {
            _property = value;
        }
    }

    public string Message
    {
        get
        {
            return _message;
        }

        private set
        {
            _message = value;
        }
    }

    public ValidationError(string property, string message)
    {
        Property = property;
        Message = message;
    }
}

剩下的就是 StructureMap 魔术了.我们需要创建验证服务层,它将定位验证对象并验证我们的实体.我想为此定义一个接口,因为我希望任何使用验证服务的人都完全不知道 StructureMap 的存在.此外,我认为在引导程序逻辑之外的任何地方都使用 ObjectFactory.GetInstance() 是一个坏主意.保持集中是确保良好可维护性的好方法.无论如何,我在这里使用装饰器模式:

The rest of this is StructureMap magic. We need to create validation service layer which will locate validation objects and validate our entity. I'd like to define an interface for this, since i want anyone using validation service to be completely unaware of the StructureMap presence. Besides, i think sprinkling ObjectFactory.GetInstance() anywhere besides the bootstrapper logic a bad idea. Keeping it centralized is a good way to insure good maintainability. Anyway, i use the decorator pattern here:

public interface IValidationService
{
    ValidationState Validate<TEntity>(TEntity entity);
}

我们终于实现了它:

public class ValidationService : IValidationService
{
    #region IValidationService Members

    public IValidator<TEntity> GetValidatorFor<TEntity>(TEntity entity)
    {
        return ObjectFactory.GetInstance<IValidator<TEntity>>();
    }

    public ValidationState Validate<TEntity>(TEntity entity)
    {
        IValidator<TEntity> validator = GetValidatorFor(entity);

        if (validator == null)
        {
            throw new Exception("Cannot locate validator");
        }

        return validator.Validate(entity);
    }

    #endregion
}

我将在我的控制器中使用验证服务.我们可以将它移到服务层,让 StructureMap 使用属性注入将控制器的 ModelState 实例注入到服务层,但我不希望服务层与 ModelState 耦合.如果我们决定使用另一种验证技术怎么办?这就是为什么我宁愿把它放在控制器中.这是我的控制器的样子:

I'm going to be using validation service in my controller. We could move it to the service layer and have StructureMap use property injection to inject an instance of controller's ModelState to the service layer, but i don't want the service layer to be coupled with ModelState. What if we decide to use another validation technique? This is why i'd rather put it in the controller. Here is what my controller looks like:

public class PostController : Controller
{
    private IEntityService<Post> _service = null;
    private IValidationService _validationService = null;

    public PostController(IEntityService<Post> service, IValidationService validationService)
    {
        _service = service;
        _validationService = validationService;
    }
}

这里我使用 StructureMap 注入我的服务层和验证服务实例.因此,我们需要在 StructureMap 注册表中注册两者:

Here i am injecting my service layer and validaton service instances using StructureMap. So, we need to register both in StructureMap registry:

    ForRequestedType<IValidationService>()
       .TheDefaultIsConcreteType<ValidationService>();

    ForRequestedType<IValidator<Post>>()
            .TheDefaultIsConcreteType<PostValidator>();

就是这样.我没有展示我如何实现 PostValidator,但它只是实现 IValidator 接口并在 Validate() 方法中定义验证逻辑.剩下要做的就是调用验证服务实例来检索验证器,调用实体上的验证方法并将任何错误写入 ModelState.

That's it. I don't show how i implement my PostValidator, but it's simply implementing IValidator interface and defining validation logic in the Validate() method. All that's left to do is call your validation service instance to retrieve the validator, call the validate method on your entity and write any errors to ModelState.

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create([Bind(Exclude = "PostId")] Post post)
    {
        ValidationState vst = _validationService.Validate<Post>(post);

        if (!vst.IsValid)
        {
            foreach (ValidationError error in vst.Errors)
            {
                this.ModelState.AddModelError(error.Property, error.Message);
            }

            return View(post);
        }

        ...
    }

希望我能帮到别人:)

这篇关于我的 MVC 存储库模式和 StructureMap 的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆