Use predefined vs. custom enums to return appropriate message from service layer In my project I used N Layer Architecture.

In the service layer I return  an enum  for each action, for example for Add action I have an enum like this :

  public enum AddStatus
{
    AddSuccessful,
    Faild,
    Exists
}


And for Edit I have this :

    public enum EditStatus
{
    Successful,
    Faild,
    NotFound,
    Exists
}


But sometimes I need a custom enum like this one :

    public enum AddAssetFunctionStatus
{
    AddSuccessful,
    Faild,
    Exists,
    ValueIsLess,
    ItIsNotStatistical
}


and with custom enum I can show the appropriate message to the end user. 

Another way I use, which I think is good, is to pass an out string param to each action, like :

   AddStatus Add(AddAccessDeviceViewModel accessDeviceViewModel,out string message);


And in the controller I have :

 switch (result)
        {
            case AddStatus.AddSuccessful:
                _uow.SaveChanges();
                this.AddNotification(Messages.SaveSuccessfull, NotificationType.Success);
                return RedirectToAction(MVC.Admin.AccessDevice.Index());
            case AddStatus.Faild:
                this.AddNotification(Messages.SaveFailed, NotificationType.Warning);
                break;
            case AddStatus.Exists:
                this.AddNotification(Messages.DataExists, NotificationType.Info);
                break;

        }


Which one is better?


Use custom enum for each action that I need.
pass an out param to the action that I need.
I would not recommend using this pattern, personally. What you're effectively trying to do is signal error state, where 0 is null state and therefore success, similar to the way that you might do it with the Win32 API. The designers of c# and the .NET framework explicitly sought to avoid this pattern (and deem it to be an anti pattern). I think it works great for OS level work, and clearly does for both Windows and Linux, but it can be very cumbersome. 

The "c#" method of doing this is by using exceptions. For a method called SaveChanges, the return type is usually either void or bool. I personally recommend void, because bool doesn't give any context for what caused the operation to fail, and is really just a slim version using an enumeration. 

For the remainder of cases, there is USUALLY a built in exception type that is appropriate. InvalidOperationException can be used to state that you can't save the changes because the entity already exists, for instance. In a Web API, you can return something in one of the error ranges for this case.

If you really look at the exception model,  I believe you'll find that it does provide a decent solution to this problem for you. It liberates you from having to build complex enumerations, and mapping them across layers. Your application is then free to focus on interactions with the layer it communicates with, and you don't need to build extra services across each tier to describe what happened. Ideally, this means easier long term maintenance as well, because changing any part of the implementation does not result in needing to update the ENTIRE implementation.