Как вернуть HTTP код формы состояния Custom Model Binder

У меня есть пользовательский связыватель модели, который извлекает реализацию интерфейса из контейнера MEF. Это реализовано следующим образом:

public class PetViewModelBinder : DefaultModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var petId = bindingContext.ValueProvider.GetValue("id");
        var container = controllerContext.HttpContext.Application[MvcApplication.PLUGINS] as CompositionContainer;
        Lazy<IPet, IPetMetadata> pet = null;
        try
        {
            pet = container.GetExport(typeof(IPet), petId);
            var petVM = new Models.PetViewModel(pet);
            bindingContext.ModelMetadata.Model = petVM;

            return base.BindModel(controllerContext, bindingContext);
        }
        catch (Exception)
        {

            throw;
        }
        finally
        {
            container.ReleaseExport(pet);
        }

    }

Это прекрасно работает, когда MEF имеет экспорт petId..., но возвращает HTTP-статус 500 (ошибка сервера), когда экспорт не существует. Требования обфускации сообщений об ошибках диктуют статус http 403 (запрещено).

Что можно сделать, чтобы перехватить ошибку, изменить статус ответа и либо не возвращать содержимое, либо перенаправить действие для обработки этого условия?

1 ответ

Решение

Если вы хотите вернуть определенный код статуса http, вы должны сделать это из контроллера или фильтра действий.

Один из способов сделать это - вернуть значение null из связывателя модели и обработать его в контроллере. Это немного грубовато, поэтому вы не сможете различить разные ошибки.

Другой способ сделать это - вызвать конкретное исключение и обработать его в вашей (глобальной) обработке ошибок. Настроенный фильтр действий HandleError может сделать это:

public class CustomHandleErrorAttribute : HandleErrorAttribute
{
  public int StatusCode { get; set; }

  public override void OnException( ExceptionContext filterContext )
  {
     base.OnException( filterContext );
     if ( StatusCode > 0 )
     {
        filterContext.HttpContext.Response.StatusCode = StatusCode;
     }
  }
}

В вашем контроллере украсьте действие этим атрибутом:

[CustomHandleError( ExceptionType = typeof (NotAllowedException), View = "~/Views/Shared/Error.cshtml",
     StatusCode = 403 )]
public ActionResult Index( FancyModel model )
{
   return View( model );
}

Наконец, в связывателе модели выдается исключение NotAllowedException, которое представляет собой пользовательский тип исключения, который также необходимо определить.

Обратите внимание, что это будет работать только в вашей настройке разработки, если вы включили пользовательские ошибки в файле web.config.

Другие вопросы по тегам