質問

過去には、UserControlsを使用してプロパティを入力できるメールテンプレートを作成し、LoadControlを使用してからRenderControlを使用して、電子メールのボディテキストに使用するHTMLを取得しました。これはASP.NET WebForms内でした。

私はMVC Webサイトを構築するスローにいますが、同様のことをしたいと思っていました。私は実際にこの機能を別々のクラスライブラリに配置することを検討し、これを行う方法を検討しているので、私のWebレイヤーでemailtemplate.subscriptionemail()を呼び出すことができます。場所(明らかに、そこにはメールアドレスなどにパラメーターが必要です)。

テンプレートであるUserControlのパスに文字列を渡すことができる単一のレンダリング制御方法を作成したかったのです。私はこれに私のニーズに合ったウェブでこれに出くわしました:

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

私の問題は、私のusercontrolが複数の異なる特性を持っている可能性があることです。したがって、SubscribeMailは、別の電子メールテンプレートusercontrol(dummyemailと呼びましょう)がfirstName、emailAddress、dateofbirthが必要な場合、firstNameとEmailAddressを必要とする場合があります。

上記のメソッドは、PropertyNameとPropertyValueの1つのパラメーターのみを搭載しているように見えます。さまざまなプロパティを入れることができる文字列の配列を考えましたが、そのような方法を呼び出すことができるように、オブジェクトをintialiserにするのはクールだと思いました。

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

それは理にかなっていますか?そもそもこれが可能かどうか疑問に思っていましたが、どのように実装していますか? 「オブジェクト」に設定されたプロパティをロードされたユーザーコントロールのプロパティにマッピングできるかどうか、そしてこれを行うことがどこから始めるかが可能かどうかはわかりません。

誰かが以前にこのようなことをしたことがありますか?誰かが助けることができますか?

ロイド

役に立ちましたか?

解決

あなたの例を実装できます。しかし、それはMVCパターンにかなり違反します。とにかくそれをしているなら、あなたはWebFormsで持っていたまったく同じソリューションを使用することもできます。

HTMLメールを作成すると、通常は通常のMVCビューを作成します(コントローラーとビューでアクションを使用します)。次に、そのビューを文字列にレンダリングして送り出します。このようにして、MVCパターンに従って、ブラウザ内のメールを自動的に表示できるようになります(そのアクションにURLにアクセスできます。これはもちろん、必要な方法で制限できます)。

文字列のビューをレンダリングするには、このクラスを使用します。

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

これは、StringBuilderのビューの結果を書く偽の応答を使用します。次に、このように使用します。

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

次に、そのボディテキストでメールを送信するだけです。もちろん、これを自分のクラスで包むことができます。これにより、emailTemplate.subscriptionemail()を呼び出すことができます。 (例から)。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top