Sending emaills with template MVC using Razor - asp.net-mvc-4

I want to send some mails from my site.
I've created a template: OrderPlacedEmail.cshtml
#model OnlineCarStore.Models.PurchaseVM
<h1>Order Placed Email Notification</h1>
<p>#Model.Comments</p>
Dear #Model.Name,
<h2>Thank you.</h2>
<p>
You’ve made a purchase on #Model.Comments
</p>....and so on...
I've created a view model, and I use it like this:
var template = Server.MapPath("~/Templates/OrderPlaced.cshtml");
var viewModel = new PurchaseVM
{
GuId = new Guid(guidValue),
Name = name,
Address = address,
Phone = phone,
Email = email,
Comments = comments,
Date = DateTime.Now,
CartList = cartList
};
var body = Razor.Parse(template, viewModel);
As I understood, the Razor.Parse method, should replace all the details from my template with the values from view model. But, the body gets the value of the location of the template, as you can see below:
Can you please advise what I'm doing wrong.

If you wish there is a helper that i use
public static class HtmlOutputHelper
{
public static string RenderViewToString(ControllerContext context,
string viewPath,
object model = null,
bool partial = false)
{
// first find the ViewEngine for this view
ViewEngineResult viewEngineResult = null;
if (partial)
viewEngineResult = ViewEngines.Engines.FindPartialView(context, viewPath);
else
viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null);
if (viewEngineResult == null)
throw new FileNotFoundException("View cannot be found.");
// get the view and attach the model to view data
var view = viewEngineResult.View;
context.Controller.ViewData.Model = model;
string result = null;
using (var sw = new StringWriter())
{
var ctx = new ViewContext(context, view,
context.Controller.ViewData,
context.Controller.TempData,
sw);
view.Render(ctx, sw);
result = sw.ToString();
}
return result;
}
}
On your controller
var viewModel = new PurchaseVM
{
GuId = new Guid(guidValue),
Name = name,
Address = address,
Phone = phone,
Email = email,
Comments = comments,
Date = DateTime.Now,
CartList = cartList
};
var emailTemplate = "~/Views/Templates/OrderPlaced.cshtml";
var emailOutput = HtmlOutputHelper.RenderViewToString(ControllerContext, emailTemplate, emailModel, false);

You also can use ActionMailerNext lib from NuGet Gallery for this scenario.
public class EmailController : MailerBase
{
//...
public EmailResult OrderPlaced(Order order)
{
MailAttributes.To.Add(new MailAddress("to#email.com"));
MailAttributes.From = new MailAddress("from#email.com");
return Email("OrderPlaced", new PurchaseVM
{
//...
});
}
//...
}
You can leave your View unchanged.

Related

Deleting one object from CartItems in razor pages

i have some products in my Cart via cookies, now i want to select and delete them from cart,
public class CartModel : PageModel
{
public List<CartItem> CartItems;
public const string CookieName = "cart-items";
public void OnGet()
{
var serializer = new JavaScriptSerializer();
var value = Request.Cookies[CookieName];
CartItems = serializer.Deserialize<List<CartItem>>(value); //error accurred in this line
foreach (var item in CartItems)
item.TotalItemPrice = item.UnitPrice * item.Count;
}
public IActionResult OnGetRemoveFromCart(long id)
{
var serializer = new JavaScriptSerializer();
var value = Request.Cookies[CookieName];
Response.Cookies.Delete(CookieName);
var cartItems = serializer.Deserialize<List<CartItem>>(value);
var itemToRemove = cartItems.FirstOrDefault(x => x.Id == id);
cartItems.Remove(itemToRemove);
var options = new CookieOptions { Expires = DateTime.Now.AddDays(2) };
Response.Cookies.Append(CookieName, serializer.Serialize(cartItems), options);
return RedirectToPage("/Cart");
}
until i don't click on the delete button, everything is ok, i don't have any error in OnGet on Cart Razor page. but when i click on the delete button and OnGetRemoveFromCart's handler is executed,CartItems is null on OnGet!
the errorr: 'Object reference not set to an instance of an object.CartItems was null.'
Response.Cookies.Delete(CookieName);
You delete the cookie in the OnGetRemoveFromCart handler, so value becomes null in the OnGet handler. You should always check for null before accessing cookie values:
public void OnGet()
{
var serializer = new JavaScriptSerializer();
var value = Request.Cookies[CookieName];
if(value is not null)
{
CartItems = serializer.Deserialize<List<CartItem>>(value);
foreach (var item in CartItems)
{
item.TotalItemPrice = item.UnitPrice * item.Count;
}
}
}

Simple serialize ODataQueryOptions

I'm trying to:
[EnableQuery]
[HttpGet]
[ODataRoute("")]
public IHttpActionResult Get(ODataQueryOptions<UserODataModel> options)
{
var users = _repository.RetrieveOData();
var serialQuery = JsonConvert.SerializeObject(options, jsonOptions);
//save serialQuery somewhere
return Ok(users);
}
But got
Newtonsoft.Json.JsonSerializationException: 'Error getting value from 'ReadTimeout' on 'Microsoft.Owin.Host.SystemWeb.CallStreams.InputStream'.'
"Timeouts are not supported on this stream."
I know there is already a question about serialize Stream:
Newtonsoft Json.net - how to serialize content of a stream?
But in this case i can't "extract stream value" from ODataQueryOptions, or can I?
Some ideia?
Since we work on the same company, if anyone is interested, we found a way, maybe not the pretty way, to serialize an ODataQueryOptions:
public static ODataQueryOptions DeserializeQueryOptions(SerializedQueryOptions options)
{
var uri = new Uri(teste.OriginalUri);
var model = ODataConfig.Model; //GetEdmModel
var segment = model.EntityContainer.FindEntitySet(options.EdmType);
var newPath = new Microsoft.AspNet.OData.Routing.ODataPath(new EntitySetSegment(segment));
var httpConfiguration = new HttpConfiguration();
httpConfiguration.EnableDependencyInjection();
var request = new HttpRequestMessage(HttpMethod.Get, uri)
{
Properties =
{
{ HttpPropertyKeys.HttpConfigurationKey, httpConfiguration },
}
};
var context = new ODataQueryContext(model, options.EntityType, newPath);
var oDataQueryOptions = new ODataQueryOptions(context, request);
return oDataQueryOptions;
}
public static SerializedQueryOptions SerializeQueryOptions(ODataQueryOptions options)
{
return new SerializedQueryOptions
{
OriginalUri = options.Request.RequestUri.AbsoluteUri,
EdmType = options.Context.NavigationSource.Name,
EntityType = options.Context.ElementClrType
};
}
After you serialize it to an object you can serialize it to a JSON string:
var queryOptionsSerialized = new SerializedQueryOptions()
{
OriginalUri = "http://localhost:25723/odata/users?$skip=0&$top=2&$orderby=fullName&$count=true",
EdmType = "users",
EntityType = typeof(UserODataModel)
};
var json = JsonConvert.SerializeObject(queryOptionsSerialized);
var deserialized = JsonConvert.DeserializeObject<SerializedQueryOptions>(json);
var options = ODataQueryOptionsHelper.DeserializeQueryOptions(deserialized);
In case One is not using OData routing or using an ApiController (not ODataController),
modify the way of Obtaining ODataPath to:
ODataUriParser parser = new ODataUriParser(model, serviceRoot, requestUri);
ODataPath path = parser.ParsePath();
//var newPath = new Microsoft.AspNet.OData.Routing.ODataPath(new EntitySetSegment(segment));
Microsoft.AspNet.OData.Routing.ODataPath newPath = new Microsoft.AspNet.OData.Routing.ODataPath(path.FirstOrDefault());
where the serviceRoot is the Url part other that the path defined in the model.

Passing list of object to Web API using RestSharp Client

I'm trying to send list of objects from MVC to WEBAPI using below methods. API is able to able receive the list from controller but, value of each item in the list is either empty/null on API side.
Can anyone please help me to fix this?
Controller Method:
private List<FCM.Models.Facility> GetFacilityDetails()
{
var url = "http://localhost:64664/";
var facilies = new List<Facility>();
facilies.Add( new Facility{ FCLT_ID = 100, FCLT_NM = "Facility 100" });
facilies.Add( new Facility{ FCLT_ID = 200, FCLT_NM = "Facility 200" });
facilies.Add( new Facility{ FCLT_ID = 300, FCLT_NM = "Facility 300" });
var json = JsonConvert.SerializeObject(facilies);
var _client = new RestClient(url);
var request = new RestRequest("api/facility/details", Method.GET) { RequestFormat = DataFormat.Json };
facilies.ForEach(fclt =>
request.AddParameter("facilites", fclt, ParameterType.GetOrPost));
var response = _client.Execute<List<FCM.Models.Facility>>(request);
if (response.Data == null)
{
throw new Exception(response.ErrorMessage);
}
return response.Data;
}
WebAPI method:
[Route("api/facility/details")]
public IEnumerable<Facility> GetFullAddress([FromUri] IEnumerable<Facility> facilities)
{
return null;
}
Like the comment suggested you maybe want to issue a POST request instead, but if you would like to send an array with a GETrequest you could do it like this (with System.Net.Http.HttpClient):
Add a Format method to you Facility class:
public class Facility
{
public int FCLT_ID { get; set; }
public string FCLT_NM { get; set; }
public string Format(int index)
{
return $"[{index}].FCLT_ID={FCLT_ID}&[{index}].FCLT_NM={FCLT_NM}";
}
}
Define a class which can format the array values:
public class FacilityList : List<Facility>
{
public string Format()
{
var builder = new StringBuilder();
for (var i = 0; i < Count; i++)
{
builder.Append(this[i].Format(i));
if(i != Count -1)
{
builder.Append("&");
}
}
return builder.ToString();
}
}
And then issue the request:
var client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:64664/"),
DefaultRequestHeaders = {Accept = {new MediaTypeWithQualityHeaderValue("application/json")}}
};
var facilities = new FacilityList
{
new Facility {FCLT_ID = 100, FCLT_NM = "Facility 100"},
new Facility {FCLT_ID = 200, FCLT_NM = "Facility 200"},
new Facility {FCLT_ID = 300, FCLT_NM = "Facility 300"}
};
var format = facilities.Format();
var response = client.GetAsync("api/facility/details?" + format).GetAwaiter().GetResult();
var result = JsonConvert.DeserializeObject<IEnumerable<Facility>>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
This will bind to your controller action:
[Route("api/facility/details")]
public IHttpActionResult Get([FromUri] IEnumerable<Facility> facilities)
{
// Do stuff..
return Ok(facilities);
}

Am doing addcart functionality in mvc4?If i remove the single item in the cart it is not removing anything?

Am doing addcart functionality in mvc4?If i remove the single item in the cart it is not removing anything?
My controller action is.......
ManageDatabase _db = new ManageDatabase();
List<Product> cartList = new List<Product>();
public ActionResult Deletecart(int id)
{
var prod = _db.product.Find(id);
int CartLen = 0;
cartList.Remove(prod);
cartList = (List<Product>)System.Web.HttpContext.Current.Application["cartList"];
CartLen = cartList.Count;
System.Web.HttpContext.Current.Application["CartLen"] = CartLen;
return RedirectToAction("Details", "Home");
}
As you've requested to be guided by code, please do the following:
ManageDatabase _db = new ManageDatabase();
List<Product> cartList = new List<Product>();
public ActionResult Deletecart(int id) // tell me the value of id
{
// put breakpoint on next line and click DEBUG
var prod = _db.product.Find(id); // tell me the value of prod
int CartLen = 0;
cartList.Remove(prod);
// tell me the value of cartList
cartList = (List<Product>)System.Web.HttpContext.Current.Application["cartList"];
CartLen = cartList.Count;
System.Web.HttpContext.Current.Application["CartLen"] = CartLen;
return RedirectToAction("Details", "Home");
}
Once we know what your variables are, we can tell you what's wrong.

Viewbag doesn't exist

I tried to do this:
var NewViewResult = new ViewResult { ViewName = "Error", ViewBag.error = "Error Here" };
I got these two errors
Invalid initializer member declarator
The name 'ViewBag' does not exist in the current context
That is my code:
public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled) return;
string actionName = filterContext.RouteData.Values["action"].ToString();
Type controllerType = filterContext.Controller.GetType();
var method = controllerType.GetMethod(actionName);
var returnType = method.ReturnType;
if (returnType.Equals(typeof(JsonResult))) if (filterContext.Exception is CustomException) filterContext.Result = new JsonResult() { Data = ((CustomException)filterContext.Exception).Type }; else filterContext.Result = new JsonResult() { Data = OurExceptionType.GeneralException };
else if (returnType.Equals(typeof(ActionResult)) || (returnType).IsSubclassOf(typeof(ActionResult))) filterContext.Result = new ViewResult { ViewName = "Error" ViewBag.error="SomeError" };
filterContext.ExceptionHandled = true;
}
ViewBag is a dynamic property you cannot pass it like this in a ViewResult.
Set value in ViewBag like this:
var NewViewResult = new ViewResult { ViewName = "Error" };
ViewBag.error = "Error Message";
and In View, you can simply access it without passing in the ViewResult:
<span>#ViewBag.error</span>
and if you really want to pass it in ViewResult,then don't use ViewBag, do like this:
var NewViewResult = new ViewResult { ViewName = "Error" };