Frage

In der Vergangenheit habe ich UserControls verwendet, um E -Mail -Vorlagen zu erstellen, für die ich Eigenschaften füllen kann, und dann LoadControl verwenden und anschließend die CONTROL Renderrol rendern, um die HTML zu erhalten, für die ich für den Körpertext meiner E -Mail verwendet werden kann. Dies war innerhalb von ASP.NET WebForms.

Ich bin in den Würfen, eine MVC -Website zu erstellen und wollte etwas Ähnliches tun. Ich habe tatsächlich darüber nachgedacht, diese Funktionalität in eine separate Klassenbibliothek zu setzen, und untersuchen, wie ich dies tun kann, damit ich in meiner Webschicht einfach E -MailTemplate aufrufen kann. Orte (offensichtlich müssen dort Parameter für E -Mail -Adresse usw. vorhanden sein).

Ich wollte eine einzelne Render -Steuerungsmethode erstellen, für die ich eine Zeichenfolge an den Pfad der Usercontrol übergeben kann, die meine Vorlage ist. Ich bin im Internet darauf gestoßen, dass es zu meinen Bedürfnissen passt:

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();
        }

Mein Problem ist, dass meine UserControl (en) mehrere und unterschiedliche Eigenschaften haben können. Daher erfordert AbonnementEmail möglicherweise FirstName und E -MailAddress, bei dem eine andere E -Mail -Vorlage UserControl (nennen wir es Dummyemail) FirstName, E -MailAddress und Datum des Birth erfordern würde.

Die obige Methode scheint nur einen Parameter für PropertyName und PropertyValue zu tragen. Ich habe eine Reihe von Saiten in Betracht gezogen, in die ich die unterschiedlichen Eigenschaften einsetzen konnte, aber dann dachte ich, es wäre cool, einen Objekt -Intialiser zu haben, damit ich die Methode wie diese aufrufen kann:

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

Ist das sinnvoll? Ich habe mich nur gefragt, ob dies überhaupt möglich ist und wie ich es umsetzen würde. Ich bin mir nicht sicher, ob es möglich wäre, die auf "Objekt" festgelegten Eigenschaften auf Eigenschaften der geladenen Benutzersteuerung abzubilden und ob es möglich ist, wohin mit dem Anfängnis geeignet ist?

Hat jemand so etwas schon einmal getan? Kann jemand helfen?

Lloyd

War es hilfreich?

Lösung

Ihr Beispiel könnte implementiert werden. Aber es verletzt das MVC -Muster ziemlich viel. Und wenn Sie das sowieso tun, könnten Sie genauso gut mit der gleichen Lösung gehen, die Sie in Webformen hatten.

Wenn ich HTML -Mails erstelle, erstelle ich normalerweise eine normale MVC -Ansicht (mit einer Aktion auf einem Controller und einer Ansicht). Dann rendere ich diese Ansicht in eine Zeichenfolge und sende sie weg. Auf diese Weise folgen Sie dem MVC -Muster und erhalten die Möglichkeit, die Mail im Browser automatisch zu sehen (Sie können die URL einfach zu dieser Aktion besuchen. Dies kann natürlich auf jede gewünschte Weise eingeschränkt werden).

Um eine Ansicht zu einer Zeichenfolge zu vermitteln, benutze ich diese Klasse:

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 { }
        }
    }
}

Dies verwendet eine gefälschte Antwort, die das Ergebnis der Ansicht in einen StringBuilder schreibt. Dann benutzt du das so:

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

Dann senden Sie die E -Mail einfach mit diesem Körpertext. Sie können dies natürlich in Ihrer eigenen Klasse einwickeln, damit Sie EmailTemplate.SubScriptionemail () anrufen können. (aus Ihrem Beispiel).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top