MVC Validation - Keep it DRY with a service layer - What is best practice?

前端 未结 6 990
栀梦
栀梦 2020-12-29 08:23

I am trying to adhere to best multi-layer design practices, and don\'t want my MVC controller to interact with my DAL (or any IRepository for that matter). It must go throug

相关标签:
6条回答
  • 2020-12-29 08:43

    The issue here is validation in the service layer but how to get that information 'back up' to the web app. Something similar we discussed a bit back since the idea of dependency injection clearly comes into play here if a service is validating, you can't sinply call the service in the Model (for instance if IValidateableObject is implemented there you dont want to call the service directly)

    The approach taken was:

    Option 3: I didn't know about this earlier, but what appears to be a very powerful way to write validators is to use the ModelValidator class and a corresponding ModelValidatorProvider.

    ASP.NET MVC 3: Validating model when information external to the model is required

    So basically you are injecting a validator (which would then be in your service layer) to be resolved by mvc without a need to an explicit service locator call.

    0 讨论(0)
  • 2020-12-29 08:50

    Stephen advice is perfect in this scenario. Currently, I am working on a very large MVC 3.0 application with SOA and other things are involved. So in a response, you would like to fill all the necessary information and showing them to your views (of-course controller will dictate). Hope this helps.

    0 讨论(0)
  • 2020-12-29 08:55

    This is how I have done it.

    Have your service layer throw exceptions on business rule/validation rule failure. Create your own validation Exception for this, and include some properties to hold details of the validation error - (e.g. which property has the validation error, and what the message is)

    Then create an extension method on Exception which will copy the details of the error to the ModelState (I got this idea from Steve Sandersons rather excellent 'Pro Asp.Net MVC 2 Framework' book) - if you do this right, MVC will highlight invalid fields, show errors in the UI etc.

    Then your controller will contain something like this

    try
    {
        Service.DoSomeThing();
    }
    catch (Exception err)
    {
        err.CopyTo(ModelState);
    }
    

    This means that your business rules and validation are now in your service layer, and this could be re-used.

    Consider also passing DTOs / View Models to your Views, and mapping your domain objects to DTO's and (vice-versa), rather than passing your domain objects to your views.

    Then the DTOs / View Models can reside in the MVC layer, and you can decorate these with the Validation attributes, and have the controller pass these to the views - thus using the built in MVC validation.

    You will find that for any complex project, the validation you require at the UI end may be slightly different from what you require at the business rules end, so this helps seperate that.

    There is a good library called AutoMapper which makes it easy to map from your domain objects to your DTOs (and vice versa) without a lot of boilerplate code.

    0 讨论(0)
  • 2020-12-29 08:55

    It's actually not a bad thing to repeatedly run validations in a few layers (client side, server side in the controller or equivalent, and again in the business layer). It makes your code somewhat uncoupled. Ideally you'd only have to describe them in one place, but sometimes this is not possible. By failing to use data annotations, are you making it really hard on yourself if you want to do client-side validations? It seems so.

    Anyway, what I've done in the past in non-mvc applications is have most action methods return a Response object that includes a status (success, errors, warnings) and a list of validation errors, as well as any other properties required.

    You might be able to leverage the IValidateableObject interface, but this again ties you somewhat to something ASP.net-specific. Perhaps a compromise would be to consume your response object and convert to DataAnnotation-specific errors.

    0 讨论(0)
  • 2020-12-29 09:00

    I know, it seems like doing MVC validation violates DRY, but in reality.. it doesn't.. at least not for most (non-trivial) applications.

    Why? Because your view's validation requirements are quite often different from your business objects validation requirements. Your views validation concerns itself with validating that a specific view is valid, not that your business model is valid.

    Sometimes those two are the same, but if you build your app so that the view requires the business model to be valid, then you are locking yourself into this scenario. What happens if you need to split object creation into two pages? What happens if you decide to use the service layer for a web service? By locking your UI into a business layer validation scenario you severly cripple the kinds of solutions you can provide.

    The view is validation of the input, not validation of the model.

    0 讨论(0)
  • 2020-12-29 09:09

    I recommend you take advantage of the built in MVC validation by decorating your Model classes with data annotations. This is only for basic input validation which is different from processing business rules and validation. Data Annotations are great because they are useful for any consumer that is aware but don't adversely impact consumers that don't understand how to use them.

    I think you are right to use a service layer to abstract business rules and data access. You may want to do a couple of things to enhance the interaction between controller and service:

    1. Return XXXResult objects instead of void or primatives. If your service method is AddProduct then return AddProductResult or more broadly ProductServiceOperationResult. This result contains success/fail indicator as well as additional information.

    2. If you are using WCF then use Fault Contracts and exceptions.

    A typical MVC Application solution of mine looks like this:

    • MVC Website Project
    • xxx.Model (project, referenced by most layers)
    • xxx.Services (project)
    • xxx.DataAccess (project, sometimes merge with services)
    • others as needed

    Good luck!

    0 讨论(0)
提交回复
热议问题