title: How should I return a generic response and response code from all functions in a .NET MVC app?
body: <p>I want to be able to return a generic response from function calls in the business layer of my MVC application. Most of the time I see an object create function look like this </p>
  
  <pre><code> public int Create(ICNUser item)
   {
         return this._repository.Create(item);
   }
   public void Update(ICNUser item)
   {
        this._repository.Create(item);
   }
  </code></pre>
  
  <p>In this case the _repository is a repository that wraps entity framework. </p>
  
  <p>This works great for a lot of cases but I want more information to be returned and I want to have a success/failure variable and a response code for why this action failed validation. I want to optionally be able to return the inserted object or a selected object. </p>
  
  <p>An example would be a create user function that returns an email can't be blank error and or a user already exists error and based on the error I show the user a different message. </p>
  
  <p>The problem I'm running into is I want to have unit tests cover all of the possible response codes from a function without me having to go look at the code and try to figure out what the possible return values can be. What I'm doing feels like an anti-pattern. Is there a better way to accomplish all of this?</p>
  
  <p>This is what I have now.</p>
  
  <pre><code> public IGenericActionResponse&lt;ICNUser&gt; Create(ICNUser item)
   {
          return this._repository.Create(item);
   }
  
   public IGenericActionResponse Update(ICNUser item)
   {
         return this._repository.Update(item);
   }
  </code></pre>
  
  <p>Interfaces</p>
  
  <pre><code> namespace Web.ActionResponses
   {
  
  
  
  public enum ActionResponseCode
  {
      Success,
      RecordNotFound,
      InvalidCreateHash,
      ExpiredCreateHash,
      ExpiredModifyHash,
      UnableToCreateRecord,
      UnableToUpdateRecord,
      UnableToSoftDeleteRecord,
      UnableToHardDeleteRecord,
      UserAlreadyExists,
      EmailCannotBeBlank,
      PasswordCannotBeBlank,
      PasswordResetHashExpired,
      AccountNotActivated,
      InvalidEmail,
      InvalidPassword,
      InvalidPageAction
  }
  
  public interface IGenericActionResponse
  {
      bool RequestSuccessful { get; }
      ActionResponseCode ResponseCode { get; }
  }
  
  public interface IGenericActionResponse&lt;T&gt;
  {
      bool RequestSuccessful { get; }
      bool RecordIsNull{get;}
      ActionResponseCode ResponseCode { get; }
  }
  }
  </code></pre>
  
  <p>implementations</p>
  
  <pre><code>namespace Web.ActionResponses
  {
  
  public class GenericActionResponse&lt;T&gt; : IGenericActionResponse&lt;T&gt;
  {
      private bool _requestSuccessful;
      private ActionResponseCode _actionResponseCode;
      public T Item { get; set; }
      public GenericActionResponse(bool success, ActionResponseCode actionResponseCode, T item)
      {
          this._requestSuccessful = success;
          this._actionResponseCode = actionResponseCode;
          this.Item = item;
      }
  
      public GenericActionResponse(bool success, ActionResponseCode actionResponseCode)
      {
          this._requestSuccessful = success;
          this._actionResponseCode = actionResponseCode;
          this.Item = default(T);
      }
  
      public bool RecordIsNull
      {
          get
          {
              return this.Item == null;
          }
      }
  
      public bool RequestSuccessful
      {
          get
          {
              return this._requestSuccessful;
          }
      }
  
      public ActionResponseCode ResponseCode
      {
          get
          {
              return this._actionResponseCode;
          }
      }
  
  }
  
  
  
  
  public class GenericActionResponse : IGenericActionResponse
  {
      private bool _requestSuccessful;
      private ActionResponseCode _actionResponseCode;
  
      public GenericActionResponse(bool success, ActionResponseCode actionResponseCode)
      {
          this._requestSuccessful = success;
          this._actionResponseCode = actionResponseCode;
  
      }
  
      public bool RequestSuccessful
      {
          get
          {
              return this._requestSuccessful;
          }
      }
  
      public ActionResponseCode ResponseCode
      {
          get
          {
              return this._actionResponseCode;
          }
      }
  
  }}
  </code></pre>
  
  <p>MVC app</p>
  
  <pre><code>public ActionResult ValidateResetHash(string passwordResetHash)
      {
          IGenericActionResponse result = (IGenericActionResponse)this._userManager.IsValidPasswordResetHash(passwordResetHash);
  
          if (result.RequestSuccessful)
          {
              Models.PasswordChangeModel model = new Models.PasswordChangeModel();
              model.PasswordResetHash = passwordResetHash;
              return View("~/Areas/Public/Views/ResetPassword/PasswordChangeForm.cshtml", model);
          }
          else
          {
              switch (result.ResponseCode)
              {
                  case ActionResponseCode.RecordNotFound:
                      {
                          FermataFish.Models.GenericActionModel responseModel = new FermataFish.Models.GenericActionModel(true, "/Login", "Login", "You have submitted an invalid password reset link.", false);
                          return View("~/Views/Shared/GenericAction.cshtml", responseModel);
                      }
                  case ActionResponseCode.PasswordResetHashExpired:
                      {
                          FermataFish.Models.GenericActionModel responseModel = new FermataFish.Models.GenericActionModel(true, "/ResetPassword", "Reset Password", "You have submitted an expired password reset link. You must reset your password again to change it.", false);
                          return View("~/Views/Shared/GenericAction.cshtml", responseModel);
                      }
                  default:
                      {
                          FermataFish.Models.GenericActionModel responseModel = new FermataFish.Models.GenericActionModel(true, "/", "Home", "An unknown error has occured. The system administrator has been notified. Error code:" + Enum.GetName(typeof(ActionResponseCode), result.ResponseCode), false);
                          return View("~/Views/Shared/GenericAction.cshtml", responseModel);
                      }
              }
          }
      }
  </code></pre>