View Model Constructor Arguments
Its a very tight coupling between HTTP and your domain.
However I do not like classic layered architecture. I often utilizes CQS for my service API's

Your example would look like

public class GetProductQueryHandler: IQueryHandler&lt;GetProductQuery, Product&gt;
{
   private readonly DbContext db;

   public GetProductQueryHandler(DbContext db) {
      this.db = db;
   }    
   public async Task&lt;Product&gt; Handle(GetProductQuerycommand query) {
      if (!query.Id.HasValue) throw new ArgumentExpection("Id is required"); //Not accepting null for a Nullable is a bit strange

      var product = await db.Products.FindAsync(id);
      if (product == null) throw new NotFoundExcpetion("Product");

      return product;
   }
}


You can then translate the errors into HTTP codes using a Exception filter, here is an example from my current project

    public class ExceptionFilter : ExceptionFilterAttribute 
    {
        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            base.OnException(actionExecutedContext);

            var message = "Server error";
            var details = "Please contact support if the problem persists";

            var code = HttpStatusCode.InternalServerError;

            if(actionExecutedContext.Exception is ArgumentException)
            {
                code = HttpStatusCode.BadRequest;
                message = "Bad Arguments";
                details = actionExecutedContext.Exception.Message;
            }

#if DEBUG
    details =   string.Format("{0}: {1}", actionExecutedContext.Exception.Message, actionExecutedContext.Exception.StackTrace);
#endif

            var response = new
            {
                Message = message,
                Details = details
            };

            actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(code, response);
        }
    }