pls help me to get it solved. I am making a ASP .NET Core 6 MVC Application where I have to make two screens login and after validate login show profile details via WEB API call. login is successful after that I am trying to use HTTPPOST to show details into view named home/Account . here is my code in home controller :-
[HttpPost]
public async Task<IActionResult> Account(ReceivedToken token)
{
var companyForCreation = new ReceivedToken
{
email = "myemailid"
};
GetCompanyDetailsViewModel details = new GetCompanyDetailsViewModel();
using (var httpClient = new HttpClient())
{
StringContent content = new StringContent(JsonConvert.SerializeObject(companyForCreation), Encoding.UTF8, "application/json");
using (var response = await httpClient.PostAsync("webAPIURL", content))
{
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string apiResponse = await response.Content.ReadAsStringAsync();
details = JsonConvert.DeserializeObject<GetCompanyDetailsViewModel>(apiResponse);
}
else
{
//ViewBag.StatusCode = response.StatusCode;
TempData["msg"] = response.StatusCode;
}
}
}
return View(details);
}
how can i Assign this HTTPPOST method directly to my view
#model GetCompanyDetailsViewModel
#{
ViewBag.Title = "Account Page";
}
<html>
<head>
<style type="text/css">
header{display:none;}
body {
background-color: darkseagreen;
}
</style>
</head>
</html>
#if (Model != null)
{
<h2>Welcome to the web Application</h2>
#Model.bankAccount
#Model.bankName
#Model.email
}
Your view does not belong to your POST method. It belongs to GET method called Account(). So after your POST method finishes its work send data to GET method with RedirectToAction(nameOf(Account))
Related
I'm working on an ASP.NET MVC project where there will be a message service. In the header It will be possible to see how many unread message the current user is having. Anyhow the viewbag that is storing the value of unread messages is just available in views that is using #model #List<Message>. I want it to be available in every view.
So my controller is looking like this
public class MessageController : Controller
{
private CVDbContext context;
private HttpClient _httpClient; // skapa http client
public MessageController(HttpClient httpClient, CVDbContext cVDbContext)
{
this.context = cVDbContext;
this._httpClient = httpClient; // hhtp client
}
public async Task<IActionResult> Message() // async därför vihämtar data från server
{
List<SentMessage> allMessages = new();
allMessages = await GetAllMessagesAsync();
User user = context.Users.Where(x => x.UserName.Equals(User.Identity.Name)).FirstOrDefault();
List<SentMessage> myMessages = allMessages.Where(x => x.ToUserID.Equals(user.Id)).ToList();
foreach (var item in myMessages)
{
User fromuser = context.Users.Where(x => x.Id.Equals(item.FromUserID)).FirstOrDefault();
item.FromUser = fromuser;
}
myMessages.Reverse(); // för att nyast meddelanden ska visas först
List<SentMessage> msgList = await GetAllMessagesAsync();
List<SentMessage> unreadList = msgList.Where(x => x.ToUserID.Equals(user.Id) && (!x.IsSeen)).ToList(); // count unreadmessage for current user.
//return unreadList.Count().ToString();
ViewBag.UnRead = unreadList.Count().ToString(); // store unread messages in viewbag unred
return View(myMessages);
}
}
My _layout that is shared with all views is looking like this
<a class="nav-link text-dark" asp-area="" asp-controller="Message" asp-action="Message"> Meddelanden #ViewBag.UnRead</a>
My view that is displaying what I want look like this
#model List<SentMessage>
#{
#if (User.Identity.IsAuthenticated)
{
Layout = "~/Views/Shared/_Layout.cshtml";
}
else
{
Layout = "~/Views/Shared/_LoginPartial.cshtml";
}
}
Those views where this does not work is all that is not using Model of Message. So my question is if there is any way i can get this data from this view and send it to all other views?
And yes the message model is called sentmessage.
I have designed an Email Template from Razor Syntax. When I send this template as Email using C# code and SMTP protocol, I get bare Razor and HTML markups as Email Body. Am I wrong in this approach? Are Razor Pages allowed as Email Template?
Here is my Page
#inherits ViewPage
#{
Layout = "_Layout";
ViewBag.Title = "";
}
<div class="container w-420 p-15 bg-white mt-40">
<div style="border-top:3px solid #22BCE5"> </div>
<span style="font-family:Arial;font-size:10pt">
Hello <b>{UserName}</b>,<br /><br />
Thanks for Registering to XYZ Portal<br /><br />
<a style="color:#22BCE5" href="{Url}">Click to Confirm Email</a><br />
<br /><br />
Thanks<br />
Admin (XYZ)
</span>
Update..
using (StreamReader reader = new StreamReader(HttpContext.Current.Server.MapPath("~/ContentPages/EmailConfTemplate.cshtml")))
{
body = reader.ReadToEnd();
//Replace UserName and Other variables available in body Stream
body = body.Replace("{UserName}", FirstName);
}
Later On I am replacing the SMTP Code as ..
MailMessage message = new MailMessage(
ApplicationWideData.fromEmailId, // From field
ToEmailId, // Recipient field
"Click On HyperLink To Verify Email Id", // Subject of the email message
body
);
You do not need any special libraries to render a Razor view to a string in an ASP.NET MVC application.
Here is how you do it in MVC Core 3
public static class ViewToStringRenderer
{
public static async Task<string> RenderViewToStringAsync<TModel>(IServiceProvider requestServices, string viewName, TModel model)
{
var viewEngine = requestServices.GetRequiredService(typeof(IRazorViewEngine)) as IRazorViewEngine;
ViewEngineResult viewEngineResult = viewEngine.GetView(null, viewName, false);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + string.Join("\r\n", viewEngineResult.SearchedLocations));
}
else
{
IView view = viewEngineResult.View;
var httpContextAccessor = (IHttpContextAccessor)requestServices.GetRequiredService(typeof(IHttpContextAccessor));
var actionContext = new ActionContext(httpContextAccessor.HttpContext, new RouteData(), new ActionDescriptor());
var tempDataProvider = requestServices.GetRequiredService(typeof(ITempDataProvider)) as ITempDataProvider;
using var outputStringWriter = new StringWriter();
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model },
new TempDataDictionary(actionContext.HttpContext, tempDataProvider),
outputStringWriter,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return outputStringWriter.ToString();
}
}
}
In the controller
string str = await ViewToStringRenderer.RenderViewToStringAsync(HttpContext.RequestServices, $"~/Views/Emails/MyEmailTemplate.cshtml", new MyEmailModel { Prop1 = "Hello", Prop2 = 23 });
In ConfigureServices() in Startup.cs
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Here is how you do it in MVC 5
public static class ViewToStringRenderer
{
public static string RenderViewToString<TModel>(ControllerContext controllerContext, string viewName, TModel model)
{
ViewEngineResult viewEngineResult = ViewEngines.Engines.FindView(controllerContext, viewName, null);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + viewEngineResult.SearchedLocations);
}
else
{
IView view = viewEngineResult.View;
using (var stringWriter = new StringWriter())
{
var viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary<TModel>(model), new TempDataDictionary(), stringWriter);
view.Render(viewContext, stringWriter);
return stringWriter.ToString();
}
}
}
}
Then, from the controller
ViewToStringRenderer.RenderViewToString(this.ControllerContext, "~/Views/Emails/MyEmailTemplate.cshtml", model);
After you have the email content, it is easy to send the email using MailMessage and SmtpClient.
Email messages only understand two formats: plain text and HTML. Since Razor is neither, it will need to be processed by some engine, so that it gives you back the generated HTML.
That's exactly what happens when you use Razor in ASP.NET MVC, behind the scenes. The Razor file is compiled into a internal C# class, that gets executed, and the result of the execution is the string content of the HTML, that gets sent to the client.
Your problem is that you want and need that processing to run, only to get the HTML back as a string, instead of being sent to the browser. After that you can do whatever you want with the HTML string, including sending it as an e-mail.
There are several packages that include this power, and I've used Westwind.RazorHosting successfully, but you can also use RazorEngine with similar results. I would prefer RazorHosting for standalone non-web applications, and RazorEngine for web applications
Here is a (sanitized) version of some of my code - I'm using Westwind.RazorHosting to send razor-formatted emails from a windows service, using a strongly typed view.
RazorFolderHostContainer host = = new RazorFolderHostContainer();
host.ReferencedAssemblies.Add("NotificationsManagement.dll");
host.TemplatePath = templatePath;
host.Start();
string output = host.RenderTemplate(template.Filename, model);
MailMessage mm = new MailMessage { Subject = subject, IsBodyHtml = true };
mm.Body = output;
mm.To.Add(email);
var smtpClient = new SmtpClient();
await smtpClient.SendMailAsync(mm);
Have you took a look at MVC Mailer?
It's a free package available from GitHub (https://github.com/smsohan/MvcMailer)
There is a step by step guide for it too https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide
It's also on Nuget too. https://www.nuget.org/packages/MvcMailer
Essentially it will parse your razor view into html.
Check out a razor processor like RazorEngine (https://razorengine.codeplex.com/) which is available on NuGet. It processes razor to create an output, which is what you'd then use as the body of your email.
The Mailzory project is a valuable and convenient choice for sending emails which have Razor templates.
// template path
var viewPath = Path.Combine("Views/Emails", "hello.cshtml");
// read the content of template and pass it to the Email constructor
var template = File.ReadAllText(viewPath);
var email = new Email(template);
// set ViewBag properties
email.ViewBag.Name = "Johnny";
email.ViewBag.Content = "Mailzory Is Funny";
// send email
var task = email.SendAsync("mailzory#outlook.com", "subject");
task.Wait()
this project is hosted at Github. Also there is a nuget package available for Mailzory.
I have an ASP.Net Web API that is posted to from an external source. The values that are posted to the web api are used to determine the user's rights on our website. So the web api then passes the result object of my business logic as a bunch of cookies to our asp landing page. The problem is that the cookies are no longer available in the web page that the web api routed the response to.
Here is web api:
[HttpPost]
public HttpResponseMessage Reports(ReportRequest reportRequest)
{
if (reportRequest != null)
{
var reportAccess = new SwitchBL().CheckUserAccess(reportRequest);
var response = Request.CreateResponse(HttpStatusCode.Moved);
response.Headers.Location = new Uri(BaseUrl() + "/menu.aspx");
var json = JsonConvert.SerializeObject(reportAccess);
Dictionary<string, string> biscuitTin = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
foreach (var biscuit in biscuitTin)
{
var cookie =
new CookieHeaderValue(biscuit.Key, biscuit.Value ?? "")
{
Expires = DateTimeOffset.Now.AddDays(1),
Domain = Request.RequestUri.Host == "localhost" ? null : Request.RequestUri.Host,
HttpOnly = true
};
//cookierJar.Add(cookie);
response.Headers.AddCookies(new CookieHeaderValue[] {cookie} );
}
return response;
}
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
And so far my very simple aspx page always shows count = 0:
public partial class menu : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var cookieCount = Request.Cookies.Count;
}
}
The web api and aspx pages are in the same project thus hosted in one site. I do not want to use session variables and do not want to pass values in querystrings. Is there another way of passing data to the routed page from the web api or am I missing something here?
BTW, if I post to the api using Postman, the cookies are visible in the response header of the web api, so cookies are created. If I post using another web page, using Fiddler, I can see the cookies in the response of the api but then there are no cookies in the (receiving) asp page.
UPDATE
Thanks to the answer of Kai, I can now get the cookies in my route asp page as set in response.Headers.Location. I have a breakpoint in that page so I know it is being hit and cookie count is now as expected. However, the browser does not render the routed page. It remains on the original posting page. Here is the code I'm using in my post emulator page to call the web api:
protected void Page_Load(object sender, EventArgs e)
{
}
protected async void DoIt_OnClick(object sender, EventArgs e)
{
var reportRequest = new ReportRequest();
reportRequest.EmailAddress = Email.Text;
reportRequest.UserNumber = UserCode.Text;
reportRequest.MobileNumber = MobileNumber.Text;
reportRequest.Password = Password.Text;
reportRequest.Country = Country.Text;
reportRequest.AccountNumber = AccountNumber.Text;
reportRequest.AccountType = AccountType.Text;
reportRequest.ReportType = ReportType.Text == "" ? 0 : Convert.ToInt32(ReportType.Text);
reportRequest.PhoneInfo = PhoneInfo.Text;
await GoThereAsync(reportRequest);
}
public async Task<Uri> GoThereAsync(ReportRequest reportRequest)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:7789/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
var response = await client.PostAsJsonAsync<ReportRequest>("api/switch/reports", reportRequest);
if (response.IsSuccessStatusCode)
{
return response.RequestMessage.RequestUri;
}
return null;
}
}
To summarise: Emulator.aspx does POST to web api. Web API sets cookies and location to home.aspx. Home.aspx receives cookies (debug steps into code-behind) but browser remains on Emulat.aspx and does not render home.aspx.
Try CookieHeaderValue.Path = "/".
From the Microsoft Docs:
Path: Restricts the cookie to the specified path within the domain. If not specified, the path of the request URI is used.
ASP.NET
[HttpPost]
[Route("apitest")]
public string apitest([FromBody]string str)
{
Console.Writeline(str); // str is always null
return null;
}
Angular 2:
var creds = "str='testst'" ;
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
http.post('http://localhost:18937/apitest', creds, {
headers: headers
})
.map(res => res.json())
.subscribe(
(res2) => {
console.log('subsribe %o', res2)
}
);
I also tried creds = {"str":"test"}; without headers JSON.stringify() etc. without success. How do I Post data to ASP.NET?
var creds = {
str: 'testst'
};
$http.post('http://localhost:18937/apitest', JSON.stringify(creds));
No changes in Web API controller and it should work.
This is probably an issue with the way that ASP.NET and MVC handle data POSTS.
[HttpPost]
public ActionResult Index(int? id)
{
Stream req = Request.InputStream;
req.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(req).ReadToEnd();
InputClass input = null;
try
{
// assuming JSON.net/Newtonsoft library from http://json.codeplex.com/
input = JsonConvert.DeserializeObject<InputClass>(json)
}
catch (Exception ex)
{
// Try and handle malformed POST body
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
//do stuff
}
You can refer to my answer here and the referenced links as to a potential cause of the issue. There are quite a few server side web frameworks that inappropriately handle data POSTS and by default doesn't add the data to your request object.
You shouldn't [have to] try and change the behavior of your angular post, and modify headers to pretend your data post is a form post.
I have designed an Email Template from Razor Syntax. When I send this template as Email using C# code and SMTP protocol, I get bare Razor and HTML markups as Email Body. Am I wrong in this approach? Are Razor Pages allowed as Email Template?
Here is my Page
#inherits ViewPage
#{
Layout = "_Layout";
ViewBag.Title = "";
}
<div class="container w-420 p-15 bg-white mt-40">
<div style="border-top:3px solid #22BCE5"> </div>
<span style="font-family:Arial;font-size:10pt">
Hello <b>{UserName}</b>,<br /><br />
Thanks for Registering to XYZ Portal<br /><br />
<a style="color:#22BCE5" href="{Url}">Click to Confirm Email</a><br />
<br /><br />
Thanks<br />
Admin (XYZ)
</span>
Update..
using (StreamReader reader = new StreamReader(HttpContext.Current.Server.MapPath("~/ContentPages/EmailConfTemplate.cshtml")))
{
body = reader.ReadToEnd();
//Replace UserName and Other variables available in body Stream
body = body.Replace("{UserName}", FirstName);
}
Later On I am replacing the SMTP Code as ..
MailMessage message = new MailMessage(
ApplicationWideData.fromEmailId, // From field
ToEmailId, // Recipient field
"Click On HyperLink To Verify Email Id", // Subject of the email message
body
);
You do not need any special libraries to render a Razor view to a string in an ASP.NET MVC application.
Here is how you do it in MVC Core 3
public static class ViewToStringRenderer
{
public static async Task<string> RenderViewToStringAsync<TModel>(IServiceProvider requestServices, string viewName, TModel model)
{
var viewEngine = requestServices.GetRequiredService(typeof(IRazorViewEngine)) as IRazorViewEngine;
ViewEngineResult viewEngineResult = viewEngine.GetView(null, viewName, false);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + string.Join("\r\n", viewEngineResult.SearchedLocations));
}
else
{
IView view = viewEngineResult.View;
var httpContextAccessor = (IHttpContextAccessor)requestServices.GetRequiredService(typeof(IHttpContextAccessor));
var actionContext = new ActionContext(httpContextAccessor.HttpContext, new RouteData(), new ActionDescriptor());
var tempDataProvider = requestServices.GetRequiredService(typeof(ITempDataProvider)) as ITempDataProvider;
using var outputStringWriter = new StringWriter();
var viewContext = new ViewContext(
actionContext,
view,
new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model },
new TempDataDictionary(actionContext.HttpContext, tempDataProvider),
outputStringWriter,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return outputStringWriter.ToString();
}
}
}
In the controller
string str = await ViewToStringRenderer.RenderViewToStringAsync(HttpContext.RequestServices, $"~/Views/Emails/MyEmailTemplate.cshtml", new MyEmailModel { Prop1 = "Hello", Prop2 = 23 });
In ConfigureServices() in Startup.cs
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Here is how you do it in MVC 5
public static class ViewToStringRenderer
{
public static string RenderViewToString<TModel>(ControllerContext controllerContext, string viewName, TModel model)
{
ViewEngineResult viewEngineResult = ViewEngines.Engines.FindView(controllerContext, viewName, null);
if (viewEngineResult.View == null)
{
throw new Exception("Could not find the View file. Searched locations:\r\n" + viewEngineResult.SearchedLocations);
}
else
{
IView view = viewEngineResult.View;
using (var stringWriter = new StringWriter())
{
var viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary<TModel>(model), new TempDataDictionary(), stringWriter);
view.Render(viewContext, stringWriter);
return stringWriter.ToString();
}
}
}
}
Then, from the controller
ViewToStringRenderer.RenderViewToString(this.ControllerContext, "~/Views/Emails/MyEmailTemplate.cshtml", model);
After you have the email content, it is easy to send the email using MailMessage and SmtpClient.
Email messages only understand two formats: plain text and HTML. Since Razor is neither, it will need to be processed by some engine, so that it gives you back the generated HTML.
That's exactly what happens when you use Razor in ASP.NET MVC, behind the scenes. The Razor file is compiled into a internal C# class, that gets executed, and the result of the execution is the string content of the HTML, that gets sent to the client.
Your problem is that you want and need that processing to run, only to get the HTML back as a string, instead of being sent to the browser. After that you can do whatever you want with the HTML string, including sending it as an e-mail.
There are several packages that include this power, and I've used Westwind.RazorHosting successfully, but you can also use RazorEngine with similar results. I would prefer RazorHosting for standalone non-web applications, and RazorEngine for web applications
Here is a (sanitized) version of some of my code - I'm using Westwind.RazorHosting to send razor-formatted emails from a windows service, using a strongly typed view.
RazorFolderHostContainer host = = new RazorFolderHostContainer();
host.ReferencedAssemblies.Add("NotificationsManagement.dll");
host.TemplatePath = templatePath;
host.Start();
string output = host.RenderTemplate(template.Filename, model);
MailMessage mm = new MailMessage { Subject = subject, IsBodyHtml = true };
mm.Body = output;
mm.To.Add(email);
var smtpClient = new SmtpClient();
await smtpClient.SendMailAsync(mm);
Have you took a look at MVC Mailer?
It's a free package available from GitHub (https://github.com/smsohan/MvcMailer)
There is a step by step guide for it too https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide
It's also on Nuget too. https://www.nuget.org/packages/MvcMailer
Essentially it will parse your razor view into html.
Check out a razor processor like RazorEngine (https://razorengine.codeplex.com/) which is available on NuGet. It processes razor to create an output, which is what you'd then use as the body of your email.
The Mailzory project is a valuable and convenient choice for sending emails which have Razor templates.
// template path
var viewPath = Path.Combine("Views/Emails", "hello.cshtml");
// read the content of template and pass it to the Email constructor
var template = File.ReadAllText(viewPath);
var email = new Email(template);
// set ViewBag properties
email.ViewBag.Name = "Johnny";
email.ViewBag.Content = "Mailzory Is Funny";
// send email
var task = email.SendAsync("mailzory#outlook.com", "subject");
task.Wait()
this project is hosted at Github. Also there is a nuget package available for Mailzory.