Pergunta

No passado, usei o UserControls para criar modelos de email nos quais posso preencher propriedades e usar o LoadControl e, em seguida, renderizar o Control para obter o HTML para o qual usar para o texto corporal do meu email. Isso estava dentro do ASP.NET WebForms.

Estou nos lances de construção de um site do MVC e queria fazer algo semelhante. Na verdade, pensei em colocar essa funcionalidade em uma biblioteca de classe separada e estou analisando como posso fazer isso para que, na minha camada da web, eu possa chamar o emailTemplate.SubScriptionEmail () que então gerará o HTML do meu modelo com propriedades em relevantes Lugares (obviamente, é preciso haver parâmetros para endereço de e -mail etc.).

Eu queria criar um único método de controle de renderização para o qual posso passar uma string para o caminho do UserControl, que é o meu modelo. Eu me deparei com isso na web que combina com minhas necessidades:

public static string RenderUserControl(string path,
                 string propertyName, object propertyValue)
        {
            Page pageHolder = new Page();
            UserControl viewControl =
               (UserControl)pageHolder.LoadControl(path);

            if (propertyValue != null)
            {
                Type viewControlType = viewControl.GetType();
                PropertyInfo property = viewControlType.GetProperty(propertyName);
                if (property != null)
                    property.SetValue(viewControl, propertyValue, null);
                else
                {
                    throw new Exception(string.Format(
                       "UserControl: {0} does not have a public {1} property.",
                       path, propertyName));
                }
            }

            pageHolder.Controls.Add(viewControl);
            StringWriter output = new StringWriter();
            HttpContext.Current.Server.Execute(pageHolder, output, false);
            return output.ToString();
        }

Meu problema é que meu (s) userControl (s) pode ter várias e diferentes propriedades. Portanto, o SubscriMeeMAil pode exigir o primeiro nome e o emailddress, onde outro modelo de email UserControl (vamos chamá -lo de correio) exigiria o primeiro nome, e -mailddress e dateOfbirth.

O método acima parece transportar apenas um parâmetro para PropertyName e PropertyValue. Eu considerei uma variedade de cordas nas quais eu poderia colocar as propriedades variadas, mas então pensei que seria legal ter um intialador de objeto para que eu pudesse chamar o método como este:

RenderUserControl("EmailTemplates/SubscribeEmail.ascs", new object() { Firstname="Lloyd", Email="myemail@mydomain.com" })

Isso faz sentido? Eu estava me perguntando se isso é possível em primeiro lugar e como eu o implementaria? Não tenho certeza se seria possível mapear as propriedades definidas no 'objeto' para as propriedades no controle do usuário carregado e se for possível por onde começar a fazer isso?

Alguém já fez algo assim antes? Alguém pode ajudar?

Lloyd

Foi útil?

Solução

Seu exemplo pode ser implementado. Mas viola um pouco o padrão MVC. E se você estiver fazendo isso de qualquer maneira, poderá seguir exatamente a mesma solução que teve no Webforms.

Quando crio e -mails HTML, geralmente crio uma visualização normal do MVC (com uma ação em algum controlador e uma visualização). Então eu renderizo essa visão em uma string e a envio. Dessa forma, você está seguindo o padrão MVC e obtém a capacidade de ver o correio no navegador automaticamente (você pode apenas visitar o URL a essa ação. Isso pode ser restrito da maneira que desejar).

Para prestar uma visão a uma string, eu uso esta classe:

public class ViewRenderer
{
    protected RouteCollection RouteCollection { get; private set; }

    public DefaultViewRenderer()
        : this(RouteTable.Routes)
    {

    }

    public DefaultViewRenderer(RouteCollection routeCollection)
    {
        RouteCollection = routeCollection;
    }

    public virtual string RenderViewAsString<TController>(Expression<Action<TController>> action)
        where TController : Controller
    {
        var sb = new StringBuilder();
        var memWriter = new StringWriter(sb);

        var fakeContext = CreateFakeContext(memWriter);

        var oldContext = HttpContext.Current;
        HttpContext.Current = fakeContext;

        CreateHtmlHelper(fakeContext).RenderAction(action);

        HttpContext.Current = oldContext;

        memWriter.Flush();
        memWriter.Dispose();
        return sb.ToString();
    }

    protected virtual HttpContext CreateFakeContext(StringWriter memWriter)
    {
        var fakeResponse = new HttpResponse(memWriter);
        var context = new HttpContext(HttpContext.Current.Request, fakeResponse);

        foreach (var key in HttpContext.Current.Items.Keys)
            context.Items[key] = HttpContext.Current.Items[key];

        foreach (string key in HttpContext.Current.Session.Keys)
            context.Session[key] = HttpContext.Current.Session[key];

        return context;
    }

    protected virtual HtmlHelper CreateHtmlHelper(HttpContext fakeContext)
    {
        var fakeControllerContext = CreateControllerContext(fakeContext, RouteCollection);
        return new HtmlHelper(new ViewContext(fakeControllerContext,
                                                  new FakeView(), new ViewDataDictionary(), new TempDataDictionary()), new FakePage());
    }

    protected virtual ControllerContext CreateControllerContext(HttpContext fakeContext, RouteCollection routeCollection)
    {
        return new ControllerContext(
            new HttpContextWrapper(fakeContext),
            routeCollection.GetRouteData(new HttpContextWrapper(HttpContext.Current)), new FakeController());
    }

    protected class FakeView : IView
    {
        public void Render(ViewContext viewContext, TextWriter writer)
        {
            throw new NotImplementedException();
        }
    }

    protected class FakeController : Controller
    {

    }

    protected class FakePage : IViewDataContainer
    {
        public ViewDataDictionary ViewData
        {
            get { return new ViewDataDictionary(); }
            set { }
        }
    }
}

Isso usa uma resposta falsa que grava o resultado da vista em um StringBuilder. Então você usa o seguinte:

var viewRenderer = new ViewRenderer();
var body = viewRenderer.RenderViewAsString<SomeController>(x => x.ActionThatRendersHtmlMail(parameters));

Então você apenas envia o e -mail com esse texto corporal. É claro que você pode envolver isso em sua própria aula para poder ligar para e -mailtemplate.subScriptionEmail (); (do seu exemplo).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top