我的MVC存储库模式和StructureMap的问题

0 structuremap model-view-controller repository-pattern

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

IEntityRepository,其中TEntity:class定义基本的CRUD成员

MyEntityRepository:IEntityRepository实现CRUD成员

IEntityService,其中TEntity:class定义返回每个成员的公共类型的CRUD成员.

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

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

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

    public PostService(IValidationDictionary validationDictionary, IEntityRepository<Post> repository)
    {
        _validationDictionary = validationDictionary;
        _repository = repository;
    }
Run Code Online (Sandbox Code Playgroud)

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

这是控制器构造器的外观(第一个创建验证对象的实例):

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

    public PostController(IEntityService<Post> service)
    {
        _service = service;
    }
Run Code Online (Sandbox Code Playgroud)

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

我感谢任何帮助:)谢谢.

小智 8

看起来循环引用与服务层依赖于Controller的ModelState和依赖于Service层的Controller这一事实有关.

我不得不重写我的验证层以使其工作.这就是我做的.

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

public interface IValidator<TEntity>
{
    ValidationState Validate(TEntity entity);
}
Run Code Online (Sandbox Code Playgroud)

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

以下是ValidationError的样子:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public interface IValidationService
{
    ValidationState Validate<TEntity>(TEntity entity);
}
Run Code Online (Sandbox Code Playgroud)

我们终于实现了它:

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

    public PostController(IEntityService<Post> service, IValidationService validationService)
    {
        _service = service;
        _validationService = validationService;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我使用StructureMap注入我的服务层和validaton服务实例.所以,我们需要在StructureMap注册表中注册:

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

    ForRequestedType<IValidator<Post>>()
            .TheDefaultIsConcreteType<PostValidator>();
Run Code Online (Sandbox Code Playgroud)

而已.我没有展示我如何实现我的PostValidator,但它只是实现了IValidator接口并在Validate()方法中定义了验证逻辑.剩下要做的就是调用验证服务实例来检索验证器,在实体上调用validate方法并将任何错误写入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);
        }

        ...
    }
Run Code Online (Sandbox Code Playgroud)

希望我帮助这个人:)