Deleting one object from CartItems in razor pages - asp.net-core

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

Related

Getting the result of Iactionresult in .net Core using nswagger studio

I have this api as you can see :
[HttpGet("CreateToken")]
public IActionResult CreateToken()
{
string tokenString = string.Empty;
tokenString = BuildJWTToken();
return Ok(new { Token = tokenString });
}
I use nswagger studio to generate my api code as you can see in my MVC core
public System.Threading.Tasks.Task CreateTokenAsync()
{
return CreateTokenAsync(System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <returns>Success</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task CreateTokenAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Default1/CreateToken");
var client_ = new System.Net.Http.HttpClient();
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = ((int)response_.StatusCode).ToString();
if (status_ == "200")
{
return;
}
else
if (status_ != "200" && status_ != "204")
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null);
}
}
finally
{
if (response_ != null)
response_.Dispose();
}
}
}
finally
{
if (client_ != null)
client_.Dispose();
}
}
This code is generated by NswaggerStudio .
So when I want to call my createtoken API as you can see i couldn't get the token in the result:
public async Task<IActionResult> Index()
{
var q = myapi.CreateTokenAsync();
ViewBag.data = q;
return View(q);
}
And the view
<div class="text-center">
<h1 class="display-4">#ViewBag.data</h1>
<p>Learn about building Web apps with ASP.NET Core.</p>
</div>
And here you can see the result
Unfortunately, you cannot return result in this way.
To return any model your returning type in method should look like something like this
[HttpGet("CreateToken")]
public IActionResult<TokenModel> CreateToken()
{
string tokenString = string.Empty;
tokenString = BuildJWTToken();
return Ok(new { Token = tokenString });
}
Check this for more information
There is an alternative solution to this with ProducesResponseType (part of Microsoft.AspNetCore.Mvc).
Setting the typeof to the correct value you wish to return, will let swagger generate the json correctly. Which in turn allows nswag studio to generate
[HttpGet("CreateToken")]
[ProducesResponseType(typeof(Token), StatusCodes.Status200OK)]
public IActionResult CreateToken()
{
string tokenString = string.Empty;
tokenString = BuildJWTToken();
return Ok(new { Token = tokenString });
}

Sending emaills with template MVC using Razor

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.

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

how to assign valueprovider to controller from Model object

I have an Edit Post action method in my MVC4 application and I am trying to unit test this action. But, the Unit test fails with "NullReferenceException". Below is the unit test FYR.
[TestMethod]
public void EditAction_Should_Redirect_When_Update_Successful()
{
// Arrange
var mockHttpContext = new Mock<HttpContextBase>();
var mockRequest = new Mock<HttpRequestBase>();
mockHttpContext.Setup(x => x.Request).Returns(mockRequest.Object);
// tell the mock to return "POST" when HttpMethod is called
mockRequest.Setup(x => x.HttpMethod).Returns("POST");
mockRequest.SetupGet(req => req.Form).Returns(new FormCollection());
var controller = GetTheController();
var id = 1;
// assign the fake context
var context = new ControllerContext(mockHttpContext.Object,
new RouteData(),
controller);
controller.ControllerContext = context;
var formValues = new MyModel() {
Id = 1,
ActivityDescription = "This is another description",
CreatedDate", Convert.ToDateTime("31-12-2014"),
UserId = 1,
IsCompleted = false
};
// Act
var result = controller.Edit(id, formValues) as RedirectToRouteResult;
// Assert
Assert.AreEqual("List", result.RouteValues["Action"]);
Assert.AreEqual(id, result.RouteValues["id"]);
}
Edit action method is below -
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MyModel item)
{
var viewResult = ValidateItem(item);
if (viewResult != null)
return viewResult;
//Unit test is failing at this step.
TryUpdateModel(item);
if (ModelState.IsValid)
{
_itemsRepository.Edit(item);
return RedirectToAction("Index");
}
else return View(item);
}
Below is the stacktrace for reference -
Test Outcome: Failed
Test Duration: 0:00:00.3306816
Result Message:
Test method MvcToDoListItemsDemo.Tests.TodoControllerTest.EditAction_Should_Redirect_When_Update_Successful threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
Result StackTrace:
at Microsoft.Web.Infrastructure.DynamicValidationHelper.DynamicValidationShim.IsValidationEnabled(HttpContext context)
at Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.IsValidationEnabled(HttpContext context)
at Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(HttpContext context, Func`1& formGetter, Func`1& queryStringGetter)
at System.Web.Helpers.Validation.Unvalidated(HttpRequest request)
at System.Web.Mvc.FormValueProviderFactory.<.ctor>b__0(ControllerContext cc)
at System.Web.Mvc.FormValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.ValueProviderFactoryCollection.<>c__DisplayClassc.<GetValueProvider>b__7(ValueProviderFactory factory)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.ControllerBase.get_ValueProvider()
at System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel model)
Could someone please advise if I am doing anything wrong here ?
Regards,
Ram
TryUpdateModel(item) gets the updated values for item from the controller's default ValueProvider, usually a System.Web.Mvc.FormValueProvider, which in turn parses them from the current POST request body. In unit tests, you can wrap the model in a DictionaryValueProvider<object> and return it as-is, like this:
var controller = GetTheController();
var requestModel = new MyModel()
{
/* .. values .. */
};
controller.ValueProvider = new DictionaryValueProvider<object>(
new Dictionary<string, object>() { { "MyModel", requestModel } }, null);
var result = controller.Edit(id) as RedirectToRouteResult;

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.