MvcMailer
MvcMailer copied to clipboard
MvcMailer and Webapi
Hello, then i send email from mvc control it is send, but then i send the same email from web api control the email come empty with empty view.
May i change something and make it works ?
Hi, without some code to reproduce the issue, I am unable to provide a direct answer.
However, since WebAPI and MVC can conflict in numerous ways, I recommend to you to create a separate MVC project which exposes only those methods which will end up sending an email. Don't expose any of the MVC internals outside this new project, just provide some simple methods which take a DTO object that contains the information you need to build your email.
This will not only help to resolve issues with MVC/WebAPI/MVCMailer, but also help provide a cleaner seperation of concerns in your architecture.
thank for your fast reply, below I attach the code:
Api control:
namespace SMS.Sender.API
{
public class AccountController : ApiController
{
[System.Web.Http.HttpGet]
public object ForgotPassword(string email)
{
AccountMailer accountMailer = new AccountMailer();
accountMailer.ResetPassword(email, newPassword).SendAsync();
return true;
}
}
}
Account Mailer class:
using Mvc.Mailer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WebMatrix.WebData;
namespace SMS.Sender.Areas.Website.Models.Mailer
{
public class AccountMailer : MailerBase
{
public AccountMailer()
{
MasterName = "_MailerLayout";
}
public virtual MvcMailMessage ResetPassword(string mailTo, string password)
{
ViewBag.Password = password;
return Populate(x =>
{
x.Subject = "sms4israel - new password";
x.ViewName = "ResetPassword";
x.To.Add(mailTo);
});
}
}
}
You may try execute you own mvcmailer code in web api. This doesn't works also from different project.
I've been able to reproduce the issue. It seems that when the controller context is created by the MailerBase, the httpcontext causes an instance of the WebApi controller context to be created, and so ViewExistsText/ViewExistsHtml return false, thus the rendering of the mail message does not happen and you get a blank mail with your original subject.
I need to see if there is any way to hack around this. I think this fundamentally arises due to the close-knit intermixing of the Razor view engine, MVC, and the HttpContext and ControllerContext. There may be a way to untie it all, but it's not terribly obvious how to use the razor engine without MVC.
@levka9 A temporary workaround could be to have your mailer project have controller actions that send emails hosted on a localhost port that your WebApi controller calls. This would in theory allow the proper controller contexts to work and still support a seperation of concerns, though it would be a little heavier in terms of resource use, as you'd have to serialize your arguments to your mail message and send them over the local loopback.
Perhaps @smsohan can comment on another way to do this, or comment on a way to create the correct controller context?
@levka9 I'm having the same issue. Where you able to figure out a workaround by any chance?
@gzurbach I just call action control from web api control. This is not ideal solution but this work.
I think I figured out a workaround (took me a few hours of digging). In my case I have:
- a Web API project exposing the REST endpoints
- an MvcMailer MVC project containing the email templates (views)
The views are simply not found from the Web API project because they are located in the referenced assembly (the MvcMailler project). It's a very common issue apparently. I fixed it by installing the EmbeddedResourceVirtualPathProvider Nuget package (https://github.com/mcintyre321/EmbeddedResourceVirtualPathProvider) and it worked (almost) out of the box!
To understand better what's going on:
- This article is a bit old but still valid: http://www.codeproject.com/Articles/15494/Load-WebForms-and-UserControls-from-Embedded-Resou
- Found there : http://stackoverflow.com/questions/16366656/mcvmailer-doesnt-see-views
Hope it helps :)
@gzurbach Finally, you call Action Control with MvcMailer from Web API control, it so ?
Yes, this is true. But this solution seems ok to me. Why do you think this is not ideal? I'm basically doing exactly what your're doing in the example above. Is what you're trying to accomplish different?
[HttpPost]
[Route("foo")]
public void PasswordChanged()
{
UserMailer userMailer = new UserMailer();
userMailer.PasswordChanged("[email protected]").Send();
}
Because then we call MVC Action Control we through over all page lifecycle :
http://www.asp.net/mvc/tutorials/mvc-5/lifecycle-of-an-aspnet-mvc-5-application
I we call Web API Control and then MVC Action Control. I thought it twice over all page lifecycle.
The ideal way is call Mvc Mailer from Web API Control then we need to call it from Web API, but context of Web API it's different from MVC Action. That why we can't call Mvc Mailer from Web API Control.
Alright I see your point. I think I will accommodate with that. MvcMailer is great, even after 2 page lifecycles! Maybe a future version will fix this issue :)