Increase value of session variable for each call to controller - c#

Each time a click on a link in the View and call an ActionResult method in the Controller, I need to increase the value of the session variable, but it's not working.
When I start the value is 17 and when I click on the link and pass 1 to the Controller I want the result to be 18 and next time I click it should be 19.
But what have I done wrong and how can I improve the code? The value is a nullable int in the ActionResult.
public ActionResult Index(int? value) {
// Session
if (Session["week"] == null)
{
// Create session
Session["week"] = week.WeekNum();
}
if (!value.HasValue)
{
weekStart = (int)Session["week"];
}
else
{
Session["week"] = + value;
weekStart = (int)Session["week"];
}
ViewBag.weekNumber = weekStart;
... the rest of the code...
}

I suggest writing a helper function to do the increment e.g.
private void IncrementWeeks(int weeks)
{
if (Session["week"] == null)
{
Session["week"] = week.WeekNum();
return;
}
int currentWeek = 0;
if (int.TryParse(Session["week"].ToString(), out currentWeek))
{
Session["week"] = (currentWeek + weeks).ToString();
}
}
Just to cover NULL checking and int conversion issues.
Here's how you could wrap getting the value from the session into a helper function too:
private int ReadWeekFromSession()
{
if (Session["week"] == null)
{
return 0;
}
int currentWeek = 0;
if (int.TryParse(Session["week"].ToString(), out currentWeek))
{
}
return currentWeek;
}
For example:
public ActionResult Index(int? value)
{
int weekStart = 0;
if (!value.HasValue)
{
weekStart = ReadWeekFromSession();
}
else
{
IncrementWeeks(value.Value);
weekStart = ReadWeekFromSession();
}
// Rest of controller code....
}

You'd increment the value just like you would from any other data source:
Retrieve the value
Modify the value
Store the new value
Which could be something as simple as:
var weekValue = int.Parse(Session["week"].ToString());
weekValue += value;
Session["week"] = weekValue;
If it's possible that the session variable isn't a valid integer, you might use int.TryParse() instead or some other means of checking for that condition.
Or to avoid using that .ToString() call, if the potential for errors with the value is small enough to use int.Parse() in the first place then I suppose you could get away with this as well:
var weekValue = Convert.ToInt32(Session["week"]);
Which is a bit more forgiving on the input types, since it has many overloads.

Related

Initialize value in dictionary only once, then just update

I'm currently working to track packages when they move between bays, these changes happen every dozen or so seconds, so I have several threads accessing some dictionaries. The idea is that the first few times, I will not have the lastBay value (the program is just starting), but when A == B for the first time, I save the value of A (the bay that the pacakage has landed into, therefore the last bay at which it has been) and then just update said value every time A == B again.
private void in_bay()
{
String line_type = getDictionaryValues("global", "line_type").getStringValue();
bool result = false;
switch (line_type)
{
case "A_1":
int A = getVariableFromBucket("A_Act").getIntValue();
int B = getVariableFromBucket("A_Next").getIntValue();
result = A == B ? true : false;
if (result)
{
setDictionaryValues("global", "lastBay", new Variable("UNSIGNED8") { binaryValue = Utils.intToByteArray(A) });
}
break;
}
setVariableInBucket("IN_BAY", BitConverter.GetBytes(result));
log("IN_BAY flag in BUCKET: " + getVariableFromBucket("IN_BAY").getBoolValue(), DEBUG);
if (getDictionaryValues("global", "lastBay").binaryValue != null)
{
log("lastBay value in global: " + getDictionaryValues("global", "lastBay").getIntValue(), DEBUG);
}
else
{
log("undefined bay",DEBUG);
}
}
I have a getDictionaryValue() function that returns the variables (or an empty one if it's not in the dictionary):
public Variable getDictionaryValues(String DictionaryName, String VarName)
{
try
{
return functionDictionary[DictionaryName][VarName];
}
catch (Exception)
{
Variable emptyVariable = new Variable()
{
additionalInfo = null,
arrivalTime = 0,
binaryValue = null,
numBits = 0,
signed = false,
varType = null
};
return emptyVariable;
}
}
and a setDictionaryValue() function that actually sets the values to the dictionary selected:
public void setDictionaryValues(String DictionaryName, String VariableName, Variable VaValue)
{
try
{
lock (GlobalConstants.filtersLock)
{
if (!functionDictionary.ContainsKey(DictionaryName))
{
functionDictionary.Add(DictionaryName, new Dictionary<String, Variable>());
}
if (!functionDictionary[DictionaryName].ContainsKey(VariableName))
{
functionDictionary[DictionaryName].Add(VariableName, Value);
}
else
{
functionDictionary[DictionaryName][VariableName] = Value;
}
}
}
catch (Exception e)
{
log("An error has ocurred when setting values to functionDictionary: "+ e,DEBUG);
throw new Exception(e.ToString());
}
}
The problem is that the first time A == B It logs correctly the values being received, but when the values change again (the package starts moving again) the code no longer displays the values of lastBay, as if the dictionary global no longer has a value for lastBay. I attach an image with a reference as to the expected results and the results obtained:
What am I missing here?
From the comment thread, it looks like the problem is that in_bay is being called on different object instances, and functionDictionary is a non-static field, so you're dealing with different dictionary instances each time.
I just want to take the opportunity to point out how much simpler your code could be if you just used classes and variables rather than adding dictionaries and "Variable" objects as a layer of abstraction.
private void in_bay()
{
string? line_type = BayState.line_type;
bool result = false;
if(line_type == "A_1")
{
int A = Bucket.A_Act;
int B = Bucket.A_Next;
result = A == B;
if (result)
{
BayState.lastBay = A;
}
}
Bucket.IN_BAY = result;
log("IN_BAY flag in BUCKET: " + Bucket.IN_BAY, DEBUG);
if (BayState.lastBay != null)
{
log("lastBay value in global: " + BayState.lastBay.Value, DEBUG);
}
else
{
log("undefined bay", DEBUG);
}
}
I can pretty much guarantee whatever "business need" is driving the desire for dictionaries and such can be accomplished in another way that still allows you to write clean and less error-prone code.

How can i get alternate data on odd/even basis inside action method using c# MVC?

I want alternate data to save in database, as i have dynamic adding fields done with html input tag
below is my code in Controller, i am getting data in list parameter in form of array.
can anyone help me what will be logic i should put?
[HttpPost]
public JsonResult Create(DTab[] list)
{
foreach (DTab d in list)
{
//DTab[] dTabs = new DTab[];
DTabViewModel dTabViewModel = new DTabViewModel();
dTabViewModel.Name = d.Name;
dTabViewModel.Email = d.Email;
dTabViewModel.Number = d.Number;
db.DTabs.Add(d);
db.SaveChanges();
}
return Json(list, JsonRequestBehavior.AllowGet);
}
Please try with the below code
[HttpPost]
public JsonResult Create(DTab[] list)
{
int a = 1; //set value as 1 and then increment
foreach (DTab d in list)
{
//DTab[] dTabs = new DTab[];
DTabViewModel dTabViewModel = new DTabViewModel();
dTabViewModel.Name = d.Name;
dTabViewModel.Email = d.Email;
dTabViewModel.Number = d.Number;
//n(n+1)
if(a%2 == 0) // for even number set this condition
{
db.DTabs.Add(d);
db.SaveChanges();
}
a++;
}
return Json(list, JsonRequestBehavior.AllowGet);
}
if(a%2 == 0) means that the loop is true (i.e. should run the code inside it)
when the value of n is a number that when divided by 2 has no remainder, i.e. any even number.
Same if(a%2 == 1) means any odd number

Throw an exception or just return a string?

Say I have this function which checks for user details
//check valid user's details.
private bool checkUserDatails(String nickname, String groupId)
{
//check nickname
if ((nickname == null || nickname.Trim().Equals("")))
{
return false;
}
//check groupId
if (groupId == null)
return false;
//convert to int
int id;
try
{
id = int.Parse(groupId);
}
catch (Exception) { return false; }
//check id
if (id < 0 | id > 100)
return false;
return true;
}
It works great, but the caller function doesn't know why the function returned false if it did. My initial thought was to create my own exceptions such as IncorrectUsernameException etc. and throw them. I could also make the return value string and just return "Incorrect username".
What's the correct C# approach to this?
Following Microsoft conventions (in some places, at least), this should look like:
private void EnsureValidDetails(string nickname, string groupId)
{
if (string.IsNullOrWhiteSpace(nickname))
{
throw new ArgumentNullException(nameof(nickname));
}
else if (string.IsNullOrEmpty(groupId))
{
throw new ArgumentNullException(nameof(groupId));
}
int parsedGroupId;
if (!int.TryParse(groupId, out parsedGroupId))
{
// or some better wording
throw new ArgumentException("GroupId is not a valid number.");
}
if (parsedGroupId < 0 || parsedGroupId > 100)
{
throw new ArgumentOutOfRangeException("GroupId must be between 0 and 100.");
}
}
Notice though, that this method is doing more than it should be doing. groupId should be an int parameter, and the method should only check for the value to be inside the valid range:
private void EnsureValidDetails(string nickname, int groupId)
{
if (string.IsNullOrWhiteSpace(nickname))
{
throw new ArgumentNullException(nameof(nickname));
}
else if (groupId < 0 || groupId > 100)
{
throw new ArgumentOutOfRangeException("GroupId must be between 0 and 100.");
}
}
Yet, this might not be the best way to actually validate this kind of stuff. It certainly works as a generic, framework-independent way, but some .NET frameworks (WPF, WCF, WinForms, ASP.NET) provide built-in ways for doing this.
You shouldn't throw an exception, as it will probably happen quite often that the value false is returned. This would cause a pretty big performance decrease. Instead you could for example use an enum, with values like correct, invalid_nickname, invalid_id and so on.
enum CheckUserDetailsResult { correct, invalid_nickname, invalid_id }
Alternatively you could provide the message via the out reference like that:
private bool checkUserDetails (String nickname, String groupId, out String message)
{
if (String.IsNullOrEmpty (nickname))
{
message = "Invalid nickname!";
return false;
}
//and so on
}

Callback function to check the state of an integer

I'm making a WP7-app for my programming class and I want to implement a callback function for checking the state of an integer and not calling the function for checking it explicitly. The integer iterates at the push of a button and when it reaches it's max input I would like to have a callback function checking this, but I'm not completely sure how to implement it.
private void Right_Button_Click(object sender, RoutedEventArgs e)
{
if (current_input <= MAX_INPUT)
{
user_input[current_input] = 3;
current_input++;
display_result();
}
}
#endregion
void display_result()
{
//will move alot of this to the a result page
DateTime time_end = DateTime.Now;
TimeSpan difference = time_end.Subtract(timer);
time_stamp = difference.ToString();
bool combination_error = true;
if (current_input == 4)
{
for (int i = 0; i < MAX_INPUT; i++)
{
if (user_input[i] != combination[i])
{
combination_error = false;
break;
}
}
if (combination_error)
{
MessageBox.Show("Correct combination The timer is " + time_stamp);
}
else
{
MessageBox.Show("Wrong combination");
}
}
}
It's after I increment current_input that I now explicitly call display result something I wish not to do and instead create a callback function for it.
You can't really put a callback function on an integer, however, you could expose your integer as a property and call a function from the property setter. Look at this example:
private int _myInteger = 0;
private int MyInteger {
get
{
return _myInteger;
}
set
{
_myInteger = value;
if (_myInteger <= MAX_INPUT)
MyCallBackFunction();
}
}
private void Right_Button_Click(object sender, RoutedEventArgs e)
{
MyInteger = MyInteger + 1;
// Do your other stuff here
}
private void MyCallBackFunction()
{
// This function executes when your integer is <= MAX_VALUE
// Do Whatever here
display_result();
}
What this is doing is exposing your integer through a private property. As long as you set the property through the setter (e.g. use the MyInteger = MyInteger + 1; syntax), you can have your setter check the condition and execute your call back function.

Asp.Net : Extended range validation

I'm using Asp.Net 2.0. I have a scenario where i need to check a user input against any of two ranges. For e.g. I need to check a textbox value against ranges 100-200 or 500-600. I know that i can hook up 2 Asp.Net RangeValidators to the TextBox, but that will try to validate the input against both the ranges, an AND condition,if you will. CustomValidator is an option, but how would I pass the 2 ranges values from the server-side. Is it possible to extend the RangeValidator to solve this particular problem?
[Update]
Sorry I didn't mention this, the problem for me is that range can vary. And also the different controls in the page will have different ranges based on some condition. I know i can hold these values in some js variable or hidden input element, but it won't look very elegant.
A CustomValidator should work. I'm not sure what you mean by "pass the 2 ranges values from the server-side". You could validate it on the server-side using a validation method like this:
void ValidateRange(object sender, ServerValidateEventArgs e)
{
int input;
bool parseOk = int.TryParse(e.Value, out input);
e.IsValid = parseOk &&
((input >= 100 || input <= 200) ||
(input >= 500 || input <= 600));
}
You will then need to set the OnServerValidate property of your CustomValidator to "ValidateRange", or whatever you happen to call it.
Is this the sort of thing you're after?
I do not believe this is possible using the standard RangeValidator control.
I did some searching and I believe your best solution is going to be to create your own CustomValidator control which you can include in your project to handle this scenario.
http://www.dotnetjunkies.ddj.com/Article/592CE980-FB7E-4DF7-9AC1-FDD572776680.dcik
You shouldn't have to compile it just to use it in your project, as long as you reference it properly.
You can use the RegularExpressionValidator with the ValidationExpression property set to
Edit: (whoops, 650 and 201 etc. were valid with the old pattern)
^(1\d{2}|200|5\d{2}|600)$
This will test the entered text for 100-200 and 500-600.
I extended the BaseValidator to achieve this. Its fairly simple once you understand how Validators work. I've included a crude version of code to demonstrate how it can be done. Mind you it's tailored to my problem(like int's should always be > 0) but you can easily extend it.
public class RangeValidatorEx : BaseValidator
{
protected override void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
if (base.RenderUplevel)
{
string clientId = this.ClientID;
// The attribute evaluation funciton holds the name of client-side js function.
Page.ClientScript.RegisterExpandoAttribute(clientId, "evaluationfunction", "RangeValidatorEx");
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range1High", this.Range1High.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range2High", this.Range2High.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range1Low", this.Range1Low.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range2Low", this.Range2Low.ToString());
}
}
// Will be invoked to validate the parameters
protected override bool ControlPropertiesValid()
{
if ((Range1High <= 0) || (this.Range1Low <= 0) || (this.Range2High <= 0) || (this.Range2Low <= 0))
throw new HttpException("The range values cannot be less than zero");
return base.ControlPropertiesValid();
}
// used to validation on server-side
protected override bool EvaluateIsValid()
{
int code;
if (!Int32.TryParse(base.GetControlValidationValue(ControlToValidate), out code))
return false;
if ((code < this.Range1High && code > this.Range1Low) || (code < this.Range2High && code > this.Range2Low))
return true;
else
return false;
}
// inject the client-side script to page
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (base.RenderUplevel)
{
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "RangeValidatorEx", RangeValidatorExJs(),true);
}
}
string RangeValidatorExJs()
{
string js;
// the validator will be rendered as a SPAN tag on the client-side and it will passed to the validation function.
js = "function RangeValidatorEx(val){ "
+ " var code=document.getElementById(val.controltovalidate).value; "
+ " if ((code < rangeValidatorCtrl.Range1High && code > rangeValidatorCtrl.Range1Low ) || (code < rangeValidatorCtrl.Range2High && code > rangeValidatorCtrl.Range2Low)) return true; else return false;}";
return js;
}
public int Range1Low
{
get {
object obj2 = this.ViewState["Range1Low"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range1Low"] = value; }
}
public int Range1High
{
get
{
object obj2 = this.ViewState["Range1High"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range1High"] = value; }
}
public int Range2Low
{
get
{
object obj2 = this.ViewState["Range2Low"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range2Low"] = value; }
}
public int Range2High
{
get
{
object obj2 = this.ViewState["Range2High"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range2High"] = value; }
}
}

Categories

Resources