Question

Dans le passé, je l'ai utilisé UserControls pour créer des modèles de courrier électronique que je peux remplir des propriétés sur puis utilisez LoadControl puis RenderControl pour obtenir le code html pour lequel utiliser pour le corps du texte de mon email. Ce fut au sein de webforms asp.net.

Je suis dans les lancers de la construction d'un site Web et mvc voulait faire quelque chose de similaire. Je l'ai fait envisagé de mettre cette fonctionnalité dans une bibliothèque séparée de classe et suis à la recherche sur la façon dont je peux le faire de telle sorte que dans ma couche web je peux appeler EmailTemplate.SubscriptionEmail () qui sera ensuite générer le code HTML à partir de mon modèle avec des propriétés en pertinentes endroits (évidemment il faut être des paramètres pour l'adresse e-mail, etc.) là-dedans.

Je voulais créer une seule méthode de contrôle de rendu pour lequel je peux passer une chaîne sur le chemin du UserControl qui est mon modèle. Je suis venu à travers ce sur le web qui convient genre de mes besoins:

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

Mon problème est que mon UserControl (s) peut avoir des propriétés multiples et différentes. Alors SubscribeEmail peut exiger FirstName et EmailAddress où un autre modèle de courrier électronique UserControl (permet de l'appeler DummyEmail) nécessiteraient FirstName, EmailAddress et DateOfBirth.

La méthode ci-dessus ne semble porter un paramètre pour propertyName et propertyValue. Je considérais comme un tableau de chaînes que je pouvais mettre les propriétés différentes en mais je pensais que ce serait cool d'avoir un intialiser objet pour que je puisse appeler la méthode comme ceci:

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

Est-ce logique? Je me demandais si cela est la mesure du possible, en premier lieu et comment je le mettre en œuvre? Je ne sais pas s'il serait possible de cartographier les propriétés définies sur « objet » aux propriétés sur le contrôle de l'utilisateur chargé et s'il est possible où commencer à faire cela?

Quelqu'un at-il fait quelque chose comme ça avant? Quelqu'un peut-il aider?

Lloyd

Était-ce utile?

La solution

Votre exemple pourrait être mis en œuvre. Mais elle viole le modèle MVC un peu. Et si vous faites cela de toute façon, vous pourriez aussi bien aller avec la même solution exacte que vous aviez en webforms.

Quand je crée mails html Je crée généralement une vue normale mvc (avec une action sur certains contrôleur et une vue). Ensuite, je rends ce point de vue dans une chaîne et de l'envoyer loin. De cette façon, vous suivez le modèle mvc et vous obtenez la possibilité de voir le courrier dans le navigateur automatiquement (vous pouvez simplement visiter l'URL pour cette action. Cela peut bien sûr être limité de quelque façon que vous voulez).

Pour rendre une vue à une chaîne que j'utilise cette 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 { }
        }
    }
}

Il utilise une réponse fausse qui écrit le résultat de la vue dans un stringbuilder. Ensuite, vous utilisez ce comme ceci:

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

Ensuite, vous envoyez juste le mail avec le texte du corps. Vous pouvez bien sûr envelopper ce dans votre propre classe de sorte que vous pouvez appeler EmailTemplate.SubscriptionEmail (); (À partir de votre exemple).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top