I wish to use C# and Razor syntax to check if a cookie has been set. If it has been set, I want to show
<h2> Cookie set </h2>.
If it hasn't, I want to display
<h2>Cookie not set</h2>
So, to review a few things, I have this setting the cookie :
//set cookie
HttpCookie cookie = Request.Cookies.Get("stackOverflowCookie");
if(cookie == null) {
cookie = new HttpCookie("stackOverflowCookie");
cookie.Value = "Hi guys!";
cookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(cookie);
Using Razor, what is the best way, syntactically, to render what I wish? Whatever I try results in compilation errors :
#{
if(Request.Cookies["stackOverflowCookie"] == null){
//some other logic is here in my actual code, so an inline statement is not sufficient
<h2> Cookie set </h2>
#}
#{ else {
<h2> Cookie not set </h2>
#}
Obviously this is horrible looking, and it doesn't work. It does show the functionality I would like those. How is the best way to achieve this functionality?
If your if statement logic is longer than a single-liner allows, you can just set a variable in a code block:
#{
var isCookieSet = Request.Cookies["stackOverflowCookie"] == null && otherConditions;
}
And then your razor code could just look like this:
#if (isCookieSet) {
<h2>Cookie set</h2>
} else {
<h2>Cookie not set</h2>
}
Just remember to be careful of putting logic in the user-interface (ie, the View).
You may wish to consider editing the View-Model to include a value of the cookie, and display the different UI depending on this variable using a simply IF statement:
#if(model.CookieProperty != null) {
<h2>Cookie is set</h2>
} else {
<h2>Cookie is not set</h2>
}
And then having the controller reading the cookie, and setting the View-Model property:
model.CookieProperty = Request.Cookies["cookieName"];
The advantages of this are:
The controller may need to "enable functionality" or perform other logic depending on this value
Testing: It's difficult to test UI elements. Easy to test a View-Model.
You could try something like
#if(Request.Cookies["stackOverflowCookie"] == null) {
<h2> Cookie set </h2>
} else {
<h2> Cookie not set </h2>
}
Related
In an ASP.NET MVC app, I have a controller action which calls business layer to add an entity.
If for business reasons, the entity could not be added, an Error property is set to true along with a description.
If true, I set a TempData key to the error message and then redirect to a view which has code to display the error stored in TempData if it exists. Sometimes the conditional block is shown and sometimes not.
Here is the relevant code in my controller
var added = ModelHelper.CreateSessionCode(model);
if(added.Error)
{
TempData["SessionCodesMessage"] = model.ErrorDescription;
TempData["MessageClass"] = "alert-danger";
}
else
{
TempData["SessionCodesMessage"] = "Created session code";
TempData["MessageClass"] = "alert-success";
}
return RedirectToAction("Index");
Then in my view I have this code:
#if (TempData["SessionCodesMessage"] != null)
{
<div class="alert #TempData["MessageClass"] alert-dismissable" style="margin-top: 8px;">
×
#(TempData["SessionCodesMessage"])
</div>
}
And it seems to be inconsistent when the message is displayed or not. Could this be a browser cache issue or similar? From stepping through the code I can confirm that the execution goes into both controller conditional blocks depending on the result of adding the entity.
Okay so, TempData is like ViewData but with a difference. It can contain data between two successive requests, but after that they are destroyed.
If you want to keep TempData value then you can use Keep:
TempData.Keep()
In your case:
var added = ModelHelper.CreateSessionCode(model);
if(added.Error)
{
TempData["SessionCodesMessage"] = model.ErrorDescription;
TempData.Keep("SessionCodesMessage");
TempData["MessageClass"] = "alert-danger";
TempData.Keep("MessageClass");
}
else
{
TempData["SessionCodesMessage"] = "Created session code";
TempData.Keep("SessionCodesMessage");
TempData["MessageClass"] = "alert-success";
TempData.Keep("MessageClass");
}
return RedirectToAction("Index");
OR
You can also use Peek if you want to be explicit about every time you want to retrieve it without having it deleted.
var added = ModelHelper.CreateSessionCode(model);
if(added.Error)
{
//second request, PEEK value so it is not deleted at the end of the request
TempData["SessionCodesMessage"]; = "Created session code";
object sessioncodevalue= TempData.Peek("SessionCodesMessage");
TempData["MessageClass"]; = "alert-success";
object messageclassvalue= TempData.Peek("MessageClass");
}
else
{
//second request, PEEK value so it is not deleted at the end of the request
TempData["SessionCodesMessage"]; = "Created session code";
object sessioncodevalue= TempData.Peek("SessionCodesMessage");
TempData["MessageClass"]; = "alert-success";
object messageclassvalue= TempData.Peek("MessageClass");
}
return RedirectToAction("Index");
You can use Peek when you always want to retain the value for another request. And use Keep when retaining the value depends on additional logic.
You can refer to this article for more information on these functions and how you can use them in your View: https://www.c-sharpcorner.com/UploadFile/ansh06031982/using-tempdata-peek-and-keep-in-Asp-Net-mvc/
I created session to move data between pages using c# asp.net but the result does not appear and the program does not give me error in the code
first page code:
Session["New1"] = desc1.Text;
to send data to Label in Second page
code:
var userType = (string)Session["New1"];
if (userType != null)
{
Label1.Text = userType.ToString() ;
}
else
{
// test "2" etc
}
Try this,
if (Session["New1"]!= null)
{
Label1.Text = Session["New1"].ToString() ;
}
else
{
// test "2" etc
}
Try explicitly checking of your Session variable exists before attempting to use it to avoid any null-reference issues :
// Explicitly check that it exists
if (Session["New1"] != null)
{
// Then grab it (if it is a non-string type, then you can use as to cast it
// (e.g. a List might use Session["List"] as List<Widget>;)
Label1.Text = Convert.ToString(Session["New1"]);
}
else
{
// Do something here
}
This assumes that your value will be set prior to this code getting called. Additionally, any hiccups to the web server (e.g. timeouts, restarts, major exceptions, etc.) will clear all of the values within the Session.
I have a multilingual web-forms web application which I am using resource files and a BasePage class which sets the culture based on the QueryString that was included in the page which is inheriting from this class. This is all working well, if a tad clunky as I am having to do this sort of thing for every button which takes the user to a different page to maintain the culture:
if (Thread.CurrentThread.CurrentCulture.ToString() == "cy-GB")
{
return "~/Secure/Details.aspx?lang=cy-GB&PersonId=" + currentPersonId;
}
else
{
return "~/Secure/Details.aspx?PersonId=" + currentPersonId;
}
I knew there was probably a better way of doing this but being a novice as it worked I simply made do.
This was until I had to implement an asp:SiteMapPath control. I initially assumed that I could simply create a resource entry for the url property like I had done for the title:
<siteMapNode
title="$resources:SiteMapLocalizations,HomePageTitle"
description="Home"
url="~$resources:SiteMapLocalizations,HomePageUrl">
However this resulted in a server error:
A potentially dangerous Request.Path value was detected from the client (:).
I've done some reading and I believe I need to somehow store the current culture to a session variable which will follow the user around so when they click 'Home' on the breadcrumb it will be consistent with the culture and grab the appropriate text from the resource files, I'm also hoping this will allow me to remove all of the IF ELSE statements I've had to write to maintain the current language throughout the application.
My question is however, where do I start with this, I cannot find any guide step by step to follow in order to achieve this, can anyone provide some instructions?
Make sure you have a button of some sort which triggers the change of language. In my case I have two versions of the header, one with an English link which will append the Query String to English and one for Welsh, something like:
ASP
<a id="languagelink" runat="server" title="Cymraeg">Cymraeg</a>
C#
if (Thread.CurrentThread.CurrentCulture.ToString() == "en-GB")
{
Uri uri = new Uri(currentPage);
languagelink.HRef = String.Format(uri.GetLeftPart(UriPartial.Path)+"?lang=cy-GB");
}
Every page which requires the language switch needs to inherit from my custom BasePage like so:
Inheritance
public partial class Secure_CustomerSummary : BasePage
Base_Page
public partial class BasePage : System.Web.UI.Page
{
protected override void InitializeCulture()
{
if (Session["language"] == null)
{
Session["language"] = "en-GB";
}
else
{
if (Request.QueryString["lang"] == null)
{
SetSessionCulture();
}
if (Request.QueryString["lang"] != null)
{
string qs = Request.QueryString["lang"];
Session["language"] = qs;
}
SetSessionCulture();
}
SetSessionCulture();
}
private void SetSessionCulture()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(Session["language"].ToString());
Thread.CurrentThread.CurrentUICulture = new CultureInfo(Session["language"].ToString());
base.InitializeCulture();
}
}
I have a several methods in controller:
public ActionResult Issue()
{
var message = WSFederationMessage.CreateFromUri(HttpContext.Request.Url);
// sign in
var signinMessage = message as SignInRequestMessage;
if (signinMessage != null)
{
return ProcessWSFederationSignIn(signinMessage, ClaimsPrincipal.Current);
}
// sign out
var signoutMessage = message as SignOutRequestMessage;
if (signoutMessage != null)
{
return ProcessWSFederationSignOut(signoutMessage);
}
return View("Error");
}
And the most valuable for me in this question:
private ActionResult ProcessWSFederationSignOut(SignOutRequestMessage message)
{
FederatedAuthentication.SessionAuthenticationModule.SignOut();
var mgr = new SignInSessionsManager(HttpContext, _cookieName);
// check for return url
if (!string.IsNullOrWhiteSpace(message.Reply) && mgr.ContainsUrl(message.Reply))
{
ViewBag.ReturnUrl = message.Reply;
}
return View("Signout");
}
All works fine, but, there are interesting moment.
This thing works in both cases, if I ended session by myself, or session simply expired. Its fine but actually, I need to tell the difference between those cases, write in ViewBag something like "You are singed out" or "Session expired" depends on result and show it oy the View.
Is there are some kind of way to detect session expired situations or should it be something different?
P.S Sorry for my bad English.
Since you changed the topic I will update my answer. I haven't used WSFederatinSession but maybe you could store the inf about how session ended (in a cookie for example) and during the next request (in a global asax for example) read this inf and do what you want to do.
I have been introduced to Razor as applied with MVC 3 this morning, so please forgive me if my question seems terribly uninformed!
I am working with an app whose workflow involves allowing a user to select a value (warehouse) from a drop down list, and add a record (material) from that warehouse to another record (Materials Request). Once the first material has been added to the Materials Request, I need to permanently set the value of the drop down to the warehouse that was first selected, then disable the drop down control (or set to read only, perhaps). The existing code in the razor file uses the DropDownListFor() method, including a ViewBag collection of Warehouse records. I have seen discussions which suggest abandoning the ViewBag design, but honestly I don't have the desire to rewrite major portions of the code; at least it looks like a major rewrite from the perspective of my experience level. Here's the original code:
#Html.LabelPlusFor(m => m.WarehouseId, "*:")
#Html.DropDownListFor(m => m.WarehouseId, (IEnumerable<SelectListItem>)ViewBag.WarehouseCodes, "")<br />
I believe I have been able to select a value based on a session object, though I'm still not sure how to disable the control. Here's my change:
#{
int SelectedWarehouseId = -1;
if (HttpContext.Current.Session["SelectedWarehouseId"] != null)
{
SelectedWarehouseId = Int32.Parse(HttpContext.Current.Session["SelectedWarehouseId"].ToString());
}
}
#Html.LabelPlusFor(m => m.WarehouseId, "*:")
#{
if (SelectedWarehouseId > -1)
{
#Html.DropDownListFor(m => m.WarehouseId, new SelectList((IEnumerable<SelectListItem>)ViewBag.WarehouseCodes, "WarehouseId", "WarehouseDescription", (int)SelectedWarehouseId))<br />
}
else
{
#Html.DropDownListFor(m => m.WarehouseId, (IEnumerable<SelectListItem>)ViewBag.WarehouseCodes, "")<br />
}
}
When the material is added to the Material Request, the WarehouseId is passed to the controller and I can access that value as "model.WarehouseId" in the controller class. However, I'm not sure how to get that value back to the View (apologies for the large code block here):
[HttpPost]
[TmsAuthorize]
public ActionResult Create(ItemRequestViewModel model)
{
string deleteKey = null;
//Removed code
else if (Request.Form["AddToRequest"] != null)
{
// If the user clicked the Add to Request button, we are only
// interested in validating the following fields. Therefore,
// we remove the other fields from the ModelState.
string[] keys = ModelState.Keys.ToArray();
foreach (string key in keys)
{
if (!_addToRequestFields.Contains(key))
ModelState.Remove(key);
}
// Validate the Item Number against the database - no sense
// doing this if the ModelState is already invalid.
if (ModelState.IsValid)
{
_codes.ValidateMaterial("ItemNumber", model.ItemNumber, model.WarehouseId);
Session["SelectedWarehouseId"] = model.WarehouseId;
}
if (ModelState.IsValid)
{
// Add the new Item Request to the list
model.Items.Add(new ItemViewModel() { ItemNumber = model.ItemNumber, Quantity = model.Quantity.Value, WarehouseId = model.WarehouseId });
ModelState.Clear();
model.ItemNumber = null;
model.Quantity = null;
model.WarehouseId = null;
}
}
//Removed code
return CreateInternal(model);
}
private ActionResult CreateInternal(ItemRequestViewModel model)
{
if (model != null)
{
if (!String.IsNullOrEmpty(model.SiteId))
{
ViewBag.BuildingCodes = _codes.GetBuildingCodes(model.SiteId, false);
if (!String.IsNullOrEmpty(model.BuildingId))
ViewBag.LocationCodes = _codes.GetLocationCodes(model.SiteId, model.BuildingId, false);
}
//Removed code
}
//Removed code
ViewBag.WarehouseCodes = _codes.GetWarehouseCodes(false);
return View("Create", model);
}
So my questions are, how do I disable the drop down list, and how can I pass a value for the selected WarehouseId back to the view? I've also considered adding the value to the ViewBag, but to be honest I don't know enough about the ViewBag to recognize any unintended consequences I may face by just randomly modifying it's contents.
Thanks for any help offered on this.
Without going into which approach is better...
Your dropdown should be rendered as an HTML select element, in order to disable this you'll need to add a disabled="disabled" attribute to it.
The DropDownListFor method has a htmlAttributes parameter, which you can use to achieve this:
new { disabled = "disabled" }
when your pass model to your view like
return View("Create", model);
if WareHouseID is set in model then
Html.DropDownListFor(x=>x.WareHouseID, ...)
will automatically set the selected value and u don't have to do that session processing for this. So far as disabling a field is required, stewart is right. you can disable drop down this way but then it won't be posted to the server when u submit the form. you can set it to readonly mode like
new{#readonly = "readOnly"}