Отображение модели ASP.NET MVC из сеанса - PullRequest
0 голосов
/ 23 октября 2018

Я загружаю письмо через Ajax, анализирую его, а затем возвращаю некоторые свойства электронной почты как частичное представление.Если пользователь отправляет форму, поля переходят к сообщению, однако в этот момент мне нужно также извлечь исходный файл, чтобы сохранить его в базе данных (поэтому я не буду хранить ничего, что загружает пользователь, только соответствующие файлы).Для этого я сохраняю поток файлов (как байт []) сообщения электронной почты в сеансе.Поскольку может быть открыто несколько страниц одновременно, я сохраняю электронные письма в сеансе в виде списка.

Затем я использую событие Validate модели для извлечения байта [] FileStream из сеанса.

public class EmailModel
{
    [Required]
    [Display(Name = "TO")]
    public string To { get; set; }
    [Display(Name = "FROM")]
    [Required]
    public string From { get; set; }
    [Display(Name = "Date")]
    public DateTime Data { get; set; }
    [Display(Name = "Location of requester")]
    public string Location { get; set; }
    [Required]
    [Display(Name = "Subject of the mail ")]
    public string SubjectMail { get; set; }
    [Required]
    [Display(Name = "Description ")]
    public string EmailBodyAsText { get; set; }
    public string EmailTypeAsString { get; set; }
    public byte[] FileStream { get; set; }
    public int ID { get; set; }
    public string KendoUniqueId { get; set; }


    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        FileStream = ExtractEmailFromSession(KendoUniqueId, HttpContext.Current.Session);
        yield return null;
    }

    private byte[] ExtractEmailFromSession(string emailId, HttpSessionState session)
    {
        if (!string.IsNullOrEmpty(emailId))
        {
            var emailList = (List<EmailInSession>)session["emailInSession"];
            return emailList.FirstOrDefault(x => x.EmailUniqueId == emailId)?.File;
        }
        else return null;
    }
}

Я думаю, что это немного вонючий код, поскольку я извлекаю контент из события, которое должно использоваться для проверки данных, поэтому я пытаюсь найти подходящее место для этого.Я знаю, что могу использовать IModelBinder для создания пользовательского связывателя, но тогда мне нужно связать все свойства, которые кажутся излишними для моей цели.В идеале я хочу использовать пользовательский атрибут только для свойства FileStream, которое извлекает данные из сеанса и возвращает их в модель.Есть ли такая возможность?

1 Ответ

0 голосов
/ 09 ноября 2018

В случае, если кто-то еще придет в эту ветку в будущем с подобной проблемой, пожалуйста, посмотрите ниже.Пожалуйста, имейте в виду, что я не мог сделать это действительно общим, поскольку это разрешает очень специфическую ситуацию.Я создал подшивку модели, которая наследует подшивку модели по умолчанию.Это позволило мне использовать базовый метод BindModel, который сделал большую часть работы за меня (обычное отображение свойств из контекста, который MVC делает для нас).Затем я выбрал конкретное свойство, которое хотел заполнить, и извлек данные из сеанса.

public class SessionModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        try
        {
            var model = (EmailModel)base.BindModel(controllerContext, bindingContext);
            model.FileStream = ExtractEmailFromSession(model.KendoUniqueId, HttpContext.Current.Session);
            return model;

        }
        catch (Exception ex)
        {
            bindingContext.ModelState.AddModelError("","No data");
            return null;
        }
    }

    private byte[] ExtractEmailFromSession(string emailId, HttpSessionState session)
    {
        if (!string.IsNullOrEmpty(emailId))
        {
            var emailList = (List<EmailInSession>)session["emailInSession"];

            return emailList?.FirstOrDefault(x => x.EmailUniqueId == emailId)?.File;
        }
        else return null;
    }

}

Кроме того, необходимо зарегистрировать скоросшиватель новой модели.Это место, где вам нужно решить, к каким моделям применяется ваша модель переплета.

public class SessionModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(Type modelType)
    {
        if (modelType == typeof(EmailModel))
            return new SessionModelBinder();
        else return null;
    }
}

Наконец, мне нужно было зарегистрировать моего нового поставщика подшивки, чтобы MVC знал об этом.Это делается путем добавления строки в глобальном asax (обратите внимание, что вам нужно поместить ее в цепочку на первой позиции - 0, в противном случае связыватель модели по умолчанию сработает, а ваша никогда не будет достигнута):

ModelBinderProviders.BinderProviders.Insert(0, new SessionModelBinderProvider());
...