문제

I've read many articles about it, and all seems to be very complex solutions. But I believe there should be an easy way to solve my problem.

I've made the Entity Framework validation for my objects with Attributes which returns an Error Message from resources (but it's not matter it's the same like ErrorMessage = ...).

[MetadataType(typeof(UserMetadata))]
public partial class User
{
     internal sealed class UserMetadata
     {
         [Required(AllowEmptyStrings = false, ErrorMessageResourceName = "UserNameRequired", ErrorMessageResourceType = typeof(ErrorMessage))]
         [StringLength(150, ErrorMessageResourceName = "UserNameLength", ErrorMessageResourceType = typeof(ErrorMessage))]
         public string UserName { get; set; }
     }
}

In my WCF Service I have the contract:

[ServiceContract]
public interface IUser
{
    [OperationContract]
    User AddUser(User user);
}

And the implementation:

public class UserService: IUser
{
    public User AddUser(User user)
    {
        //Here I think I should throw the ErrorMessage with a FaultException
        //and to catch it in the client side, but how to do it !?

        IUserRepository _user = new UserRepository(); //I've used EF Repository Pattern.
        return _user.Add(user);
    }
}
도움이 되었습니까?

해결책

The easiest way is to catch the DbEntityValidationException and convert it to a FaultException of a desired type. I'll describe a simple version of this. First create a custom fault:

[DataContract]
public class ValidationFault
{
}

Modify the service contract to indicate that the fault may be thrown:

[ServiceContract]
public interface IUser
{
    [OperationContract]
    [FaultContract(typeof(ValidationFault))]
    User AddUser(User user);
}

And modify the service code to convert the exception:

public class UserService: IUser
{
    public User AddUser(User user)
    {
        try
        {
            IUserRepository _user = new UserRepository(); //I've used EF Repository Pattern.
            return _user.Add(user);
        }
        catch (DbEntityValidationException ex)
        {
            throw new FaultException<ValidationFault>(new ValidationFault(), ex.Message);
        }
    }
}

You may also want to copy over the DbEntityValidationResult data from the EntityValidationErrors list on DbEntityValidationException. In that case you'll have to define another data contract with the fields PropertyName and ErrorMessage, and you have to write some code that copies each error message.

Of course, the annoying part is that you'll have to write this same wrapper code for every service operation. You'll soon find that you need to move the wrapper code to a helper class, but you still need to write the try-catch code every time. Where I work we've solved this and similar problems in a generalized way, using aspect-oriented programming with PostSharp. We've made an aspect called ValidationFaultAspect, which automatically converts the exception when it's applied to a method. I think it's possible to do it with the free version of PostSharp, but I'm not 100% sure.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top