处理N层,域驱动设计,MVC应用程序中的异常

goo*_*ate 1 c# domain-driven-design exception-handling

我已经构建了一个如下所示的MVC应用程序:

MVC Application - Application Layer - Business Layer - Repository - Data

我已经阅读了许多应用程序的代码,并发现没有人似乎以类似于传递数据的方式传递异常.

换句话说,数据通过接口引用并在不同的上下文中重用.如果数据层中发生异常,它将如何发送到GUI或相关层?应该使用接口吗?处理应用程序中的异常的构造是什么?

Mat*_*caj 5

我没有阅读你链接的doco但我有一个简单的例子,我提出异常以回应不满足不变量.假设我正在创建一个实例,由于某种原因它是"无效的",假设用户输入不好.而不是让我的实体处于无效状态(在DDD中是禁止的)并让系统"验证"它,它会在创建时抛出异常.相关的"验证消息"(针对用户)是从不满足的同一规范实例中提取的,并且我的派生异常包含UI所需的值.

例子InvariantException:

public class InvariantException : MyAppException
{
    public object FailingObject = null;
    public ModelStateDictionary ModelState = new ModelStateDictionary();


    public InvariantException() { }

    public InvariantException(object failingObject, ModelStateDictionary messages)
    {
        this.FailingObject = failingObject;
        this.ModelState = messages;
    }

    public InvariantException(object failingObject, ModelStateDictionary messages,
        Exception innerException)
        : base("refer to ModelState", innerException)
    {
        this.FailingObject = failingObject;
        this.ModelState = messages;
    }
}
Run Code Online (Sandbox Code Playgroud)

返回用户/ UI的相关"验证消息"的规范示例:

public class PostFieldLengthSpecification : ISpecification<Post>
{
    private  const string TITLE_LENGTH_RANGE = "5-100";
    private  const string BODY_LENGTH_RANGE = "20-10000";


    public bool IsSatisfiedBy(Post post)
    {
        return this.GetErrors(post).IsValid;
    }


    public ModelStateDictionary GetErrors(Post post)
    {
        ModelStateDictionary modelState = new ModelStateDictionary();

        if (!post.Title.Trim().Length.Within(TITLE_LENGTH_RANGE))
            modelState.AddModelError(StongTypeHelpers.GetPropertyName((Post p) => p.Title),
                "Please make sure the title is between {0} characters in length".With(TITLE_LENGTH_RANGE));

        if (!post.BodyMarkup.Trim().Length.Within(BODY_LENGTH_RANGE))
            modelState.AddModelError(StongTypeHelpers.GetPropertyName((Post p) => p.BodyMarkup),
                "Please make sure the post is between {0} characters in length".With(BODY_LENGTH_RANGE));

        return modelState;
    }
}
Run Code Online (Sandbox Code Playgroud)

工厂如何永远不会创建无效实例的示例,而是抛出异常并为UI存放消息:

    public static Post GetNewPost(string title, string bodyMarkup, DateTime posted)
    {
        var post = new Post(0, title, bodyMarkup, posted, new List<Comment>());
        var fieldLengthSpec = new PostFieldLengthSpecification();

        if (fieldLengthSpec.IsSatisfiedBy(post))
            return post;
        else
            throw new InvariantException(post, fieldLengthSpec.GetErrors(post));
    }
Run Code Online (Sandbox Code Playgroud)

最后,一个自定义模型绑定器示例,用于捕获所述异常并将"无效对象"传递回具有错误消息的操作:

public class PostModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(Post))
        {
            try
            {
                // Create Post
                return base.BindModel(controllerContext, bindingContext);
            }
            catch (InvariantException ie)
            {
                // If invalid, add errors from factory to ModelState
                bindingContext.ModelState.AddNewErrors(ie.ModelState);
                bindingContext.ModelState.AddValuesFor<Post>(bindingContext.ValueProvider);
                return ie.FailingObject;
            }
        }
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.