I am using a session helper class to track more than several variable. So far I have 30 that are needed from page to page, not all at once of course. I need to convert some of the values from single to array. The Session helper class I use is as follows. For brevity I have shown only two session variables we use for tracking tab index for two accordions.
using System;
using System.Globalization;
using System.Linq;
using System.Web;
public class SessionHelper
{
//Session variable constants
public const string AccordionTop = "#tabTop";
public const string AccordionBot = "#tabBot";
public static T Read<T>(string variable)
{
object value = HttpContext.Current.Session[variable];
if (value == null)
return default(T);
else
return ((T)value);
}
public static void Write(string variable, object value)
{
HttpContext.Current.Session[variable] = value;
}
public static int TabTop
{
get
{
return Read<int>(AccordionTop);
}
set
{
Write(AccordionTop, value);
}
}
public static int TabBot
{
get
{
return Read<int>(AccordionBot);
}
set
{
Write(AccordionBot, value);
}
}
}
So on each page I can work with variables easily as follows:
To Write:
SessionHelper.TabTop = 1; or SessionHelper.TabBot = 3
To Read:
If (SessionHelper.TabTop……….)
This all works fine. I now want to extend this to array values held in session. The array contains int, string and date time value.
For the array session object I have tried adding:
public class SessionHelper
{
public const string CompInfo = "CompAccInfo";
public static T ReadArray<T>(string variable)
{
object[] result = HttpContext.Current.Session[variable] as object[];
if (result == null)
{
return default(T);
//result = new object[30];
}
else
return ((T)(object)result);
}
public static void WriteArray(string variable, object[] value)
{
HttpContext.Current.Session[variable] = value;
}
public static object[] CompDetails
{
get
{
return ReadArray<object[]>(CompInfo);
}
set
{
WriteArray(CompInfo, value);
}
}
}
But then I get an “Object reference not set to…… error when I try to do this:
public void EGetCompanyInformation(MasterPage myMaster, int entityCode)
{
int prevEntity = 0;Using (sqlconnetiooo
.....
//I get values here this works fine
//Then:
sqlr = cmd.ExecuteReader();
sqlr.Read();
if (sqlr.HasRows)
{
//Calculate accounting period adjustment.
yearEndDiff = 12 - Convert.ToInt32(sqlr.GetDateTime(5).Month);
//Company Code.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
//Company Name.
SessionHelper.CompDetails[1] = sqlr.GetString(1);
//Currency Unit.
SessionHelper.CompDetails[2] = sqlr.GetString(2);
//Base Currency Code.
SessionHelper.CompDetails[3] = sqlr.GetString(3);
//Reporting Currency Code.
SessionHelper.CompDetails[4] = sqlr.GetString(4);
//Company Year End.
SessionHelper.CompDetails[5] = yearEndDiff;
//Country Code.
SessionHelper.CompDetails[6] = sqlr.GetString(6);
//Country Name.
SessionHelper.CompDetails[7] = sqlr.GetString(7);
//Base Currency Name.
SessionHelper.CompDetails[8] = sqlr.GetString(8);
//Report Currency Name.
SessionHelper.CompDetails[9] = sqlr.GetString(9);
//ClientID.
SessionHelper.CompDetails[10] = sqlr.GetInt32(10);
Other code here
}
}
It seems any SessionHelper.CompDetails[i] does not work : Error Object reference not set to an instance of an object.
What will happen if ReadArray will return default(T)? It will return null. Than access to any object by index inside the array will cause the exception you face.
It is not quite obvious what your code is intended to do.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
What do you want here? CompDetails itself should return an array. But you are trying to rewrite it immediately by some values.
If you want to access the CompDetails and rewrite it's objects than you have to instantiate it by
int n = 10;
SessionHelper.CompDetails = new CompDetails[n];
default(object[]) will always throw null. because the array of object is reference type and default value of any reference type is null. So accessing null value will get you Object reference not set to an instance of object.
You can change your old implementation like below:
public static T Read<T>(string variable, int arraySize=10)
{
object value = HttpContext.Current.Session[variable];
if(typeof(T).IsArray && value == null)
{
//array requires size I personally prefer to have
//differnt read method for array.
return ((T)Activator.CreateInstance(typeof(T),arraySize));
}
if(!typeof(T).IsValueType && value == null)
{
//if it is not value type you can return new instance.
return ((T)Activator.CreateInstance(typeof(T)));
}
else if (value == null)
return default(T);
else
return ((T)value);
}
And access SessionHelper as below:
var sessionarray = SessionHelper.Read<object[]>("myarray",15);
....
// then use that sessionarray here.
....
You have to instantiate the CompDetails array before you start assigning values to it.
if (sqlr.HasRows)
{
//Calculate accounting period adjustment.
yearEndDiff = 12 - Convert.ToInt32(sqlr.GetDateTime(5).Month);
// Instantiate array
SessionHelper.CompDetails = new object[11];
//Company Code.
SessionHelper.CompDetails[0] = sqlr.GetInt32(0);
// etc
Related
I have a MerchantWSBO and MerchantWSVO classes.
MerchantWSBO has a property of a type of MerchantWSVO.
I need to get a value of the property of a MerchantWSVO.
So, I have a code defining both classes(classes are coming through a WebReference from a 3rd party)
public MerchantWSBO {
private MerchantWSVO overviewField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public MerchantWSVO overview {
get {
return this.overviewField;
}
set {
this.overviewField = value;
}
}
}
public MerchantWSVO{
private System.Nullable<bool> discoverRetainedField;
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool discoverRetainedSpecified {
get {
return this.discoverRetainedFieldSpecified;
}
set {
this.discoverRetainedFieldSpecified = value;
}
}
}
I have the following method where I need to get the property value of dicoverRetained using reflection:
private string ClassToXML(Object classObject)
{
MerchantTest mt = new MerchantTest();
if(classObject is MerchantWSBO)
{
classObject.GetType().GetProperty("overviewField").GetValue(new MerchantWSVO, null);
mt.overview.discoverRetained = //need to get the value
}
var myString = new System.IO.StringWriter();
var serializer = new XmlSerializer(classObject.GetType());
serializer.Serialize(myString, classObject);
return myString.ToString();
}
Based on a parameter classObject which in this case can be of two types, I need to get a value from a property.
How can I do that?
You don't need reflection at all, simply cast the object to the correct type. Pattern matching helps here.
if(classObject is MerchantWSBO wsbo)
{
Console.WriteLine(wsbo.overview.discoverRetained);
}
or on older C# versions:
var wsbo = classObject as MerchantWSBO;
if(wsbo != null)
{
Console.WriteLine(wsbo.overview.discoverRetained);
}
I am trying to get some datetime values that are null in SQL to my C# application but i get some errors. One of the errors is:
'Unable to cast object of type 'System.DBNull' to type 'System.String'
Please, can someone tell me how to set a null DateTime value from SQL to my c# application?
I have already tried casting my C# variables to datetime value and string but both dont work. I've searched in stackoverflow but didn't found a solution for me.
I've also tried another solution but then i retrieved the date: '01/01/0001' as value instead of 'null'
public static List<Kamer> GetOpenstaandeBoekingen()
{
var result = new List<Kamer>();
using (var conn = new SqlConnection(ConnectionString))
{
conn.Open();
const string query = "select b.boekingid, k.naam, bk.incheckdatum, bk.uitcheckdatum, b.hotelid, b.aantal_gasten, bk.kamerid from boeking b join klant k on k.klantid = b.boekingid join boekingkamer bk on b.boekingid = bk.boekingid where bk.incheckdatum is null and bk.uitcheckdatum is null";
SqlCommand selectKamers = new SqlCommand(query, conn);
SqlDataReader reader = selectKamers.ExecuteReader();
while (reader.Read())
{
Kamer kamer = new Kamer((int)reader["boekingid"], (string)reader["naam"], (string)reader["incheckdatum"], (string)reader["uitcheckdatum"], (int)reader["hotelid"], (int)reader["aantal_gasten"], (int)reader["kamerid"]);
result.Add(kamer);
}
reader.Close();
}
return result;
}
And here is my class with the constructor:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FontysHotel
{
public class Kamer
{
// instantie variabelen
private int id;
private string naam;
private DateTime incheck_datum;
private DateTime uitcheck_datum;
private int hotel;
private int aantal_personen;
private int kamernr;
// properties
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
public string Naam
{
get
{
return naam;
}
set
{
naam = value;
}
}
public string Incheck_datum
{
get
{
return incheck_datum.ToShortDateString();
}
set
{
incheck_datum = Convert.ToDateTime(value);
}
}
public string Uitcheck_datum
{
get
{
return uitcheck_datum.ToShortDateString();
}
set
{
uitcheck_datum = Convert.ToDateTime(value);
}
}
public int Hotel
{
get
{
return hotel;
}
set
{
hotel = value;
}
}
public int Aantal_personen
{
get
{
return aantal_personen;
}
set
{
aantal_personen = value;
}
}
public int Kamernr
{
get
{
return kamernr;
}
set
{
kamernr = value;
}
}
public Kamer(int id, string naam, string incheck_datum, string uitcheck_datum, int hotel, int aantal_personen, int kamernr)
{
Id = id;
Naam = naam;
Incheck_datum = incheck_datum;
Uitcheck_datum = uitcheck_datum;
Hotel = hotel;
Aantal_personen = aantal_personen;
Kamernr = kamernr;
}
}
}
Uitcheckdatum and incheckdatum are the date values.
So i want, when i run the query is shows everything where are dates with null, it is for a hotel system and i want to show what bookings haven't checked in or out yet.
One way is to declare your DateTime variables as being a Nullable type, this is done by using the ? sign at the end such as this.
private DateTime? incheck_datum;
private DateTime? uitcheck_datum;
But it might be a better approach to look for, trap, and handle DB Nulls and then set default or min values like this
if (IsDBNullreader.IsDBNull(indexOfUitCheckDatum))
uitcheckdatum = DateTime.Minvalue;
else
uitcheckdatum = reader["uitcheckdatum"];
I would avoid direct initialization of an object without any previous check.
If you want to treat a DBNull value from the database as a null DateTime, there's no other option than declaring your two fields in the Kamer class using the nullable version DateTime? instead, since DateTime alone is a struct, a value type, which cannot be null. With that, you could do:
set
{
uitcheck_datum = string.IsNullOrEmpty(value) ? null : Convert.ToDateTime(value);
}
And in the loop:
while (reader.Read())
{
string incheckdatum = reader["incheckdatum"] as string;
string uitcheckdatum = reader["uitcheckdatum"] as string;
Kamer kamer = new Kamer((int)reader["boekingid"], (string)reader["naam"],
incheckdatum, uitcheckdatum, (int)reader["hotelid"],
(int)reader["aantal_gasten"], (int)reader["kamerid"]);
result.Add(kamer);
}
as saves you from possible casting exceptions. The indexer returns an instance of object. If it can't be cast to string, then null is returned.
In case you don't want to declare those fields as DateTime?, then just replace null in the set with a dummy date of your choice, e.g. DateTime.Now.
Also, make sure the string you receive from the database is a convertable string, or Convert will throw an exception. Maybe you'd want to add a try-catch to handle it.
Using .NET Core, I am trying to save and retrieve a JSON Array of the object from Redis using IDistributedCache. Below is my code for storing and reading from Redis cache:
public void Save(string key, object content, int duration)
{
string s;
if (content is string)
{
s = (string)content;
}
else
{
s = JsonConvert.SerializeObject(content);
}
duration = duration <= 0 ? DefaultCacheDuration : duration;
Cache.Set(key, Encoding.UTF8.GetBytes(s), new DistributedCacheEntryOptions()
{
AbsoluteExpiration = DateTime.Now + TimeSpan.FromSeconds(duration)
});
}
public T Get<T>(string key) where T : class
{
var c = Cache.Get(key);
if (c == null)
{
return null;
}
var str = Encoding.UTF8.GetString(c);
if (typeof(T) == typeof(string))
{
return str as T;
}
return JsonConvert.DeserializeObject<T>(str);
}
the object that I want to store is
public class RuleLoadCollection_Result
{
[Key]
public int RuleId { get; set; }
public string RuleName { get; set; }
}
In my biz logic, am saving the object like this
public IQueryable<RuleLoadCollection_Result> GetRuleLibrary()
{
var result = _dbClient.GetRuleLibrary();
_cache.Save("TestKey", result);
return result;
}
the output here is an Array of Object.
[{"ruleId":1,"ruleName":"a1"}]
What code should I write to return the same array of objects from cache? I tried a few options, most of them gave compile or runtime errors. After the bit of browsing, I tried below, it worked, but it is giving only the first element of the array.
public RuleLoadCollection_Result GetRuleLibraryFromCache()
{
return (_cache.Get<List<RuleLoadCollection_Result>>("TestKey").First());
}
output for this is
{"ruleId":1,"ruleName":"a1"}
which I understand why, but what c# should I write to JSON array back which I saved?
below code gives the runtime error
public IQueryable<RuleLoadCollection_Result> GetRuleLibraryFromCache()
{
return (_cache.Get<IQueryable<RuleLoadCollection_Result>>("TestKey"));
}
the runtime error is:
Cannot create and populate list type System.Linq.IQueryable`1[RuleLoadCollection_Result]. Path '', line 1, position 1.
This worked.
public IQueryable<RuleLoadCollection_Result> GetRuleLibraryFromCache()
{
var result = _cache.Get<IEnumerable<RuleLoadCollection_Result>>("TestKey").AsQueryable();
return result;
}
Is it possible to have 2 definitions for the this method? I want users to be able to do both of the following: string value = myBranch[stringKey]; and also Branch child = myBranch[stringKey].
Is this possible? And if not can you suggest how I could design my class to achieve the same outside interaction (ie, accessing a child branch or value easily)?
public class Branch {
public enum BranchType {TYPE_BRANCH, TYPE_LEAF}
private string key = null;
private string value = null;
private Branch parent = null;
private Dictionary <string, Branch> children = new Dictionary <string, Branch>();
// Is it possible to have 2 'this' definitions?
// Def 1:
public Branch this[string attribKey] {
get
{
if (this.children.ContainsKey(attribKey))
return this.children[attribKey];
return Branch.EmptyBranch;
}
set
{
children[attribKey] = value;
value.Parent = this;
this.Type = BranchType.TYPE_BRANCH;
}
}
// Def 1:
public string this[string attribKey] {
get
{
return value;
}
set
{
value = value;
}
}
public string Key {
get { return key; }
}
}
No, the one rule for overloads is that Overloads cannot differ only by return value. Since myBranch is probably a Dictionary, it doesn't make sense that it would sometimes return a string and sometimes a Branch. I would write two functions:
GetBranchByKey and GetStringByKey to solve the overload problem.
I was looking for a similar way to create an alias for something else like its possible in C using preprocessor (this question is a bit similar, couldn't find anything useful there).
This is the problem: I've got a method that receives an array, but each position of the array has a specific meaning, like they where different parameters with specific names. What I want to do is to make my code easier to read (and write) by using those specific names, but, on the other hand, I don't want to create another method call (like in example 1) nor assign the array positions to new variables (example 2), because the performance is critical.
Example 1:
void OriginalMethodSignature(Type[] values)
{
SimplifiedMethod(values[0], values[1], ... values[n]);
}
void SimplifiedMethod(Type specificName1, Type specificName2, ... Type specificNameN)
{
// simple implementation using specific names instead of values[n]
}
Example 2:
void OriginalMethodSignature(Type[] values)
{
Type specificName1 = values[0];
Type specificName2 = values[1];
...
Type specificNameN = values[n];
// simple implementation using specific names instead of values[n]
}
I cannot change the method signature because its used in a dellegate, the Type is fixed.
The next example is a bit better, but still not optimum:
void OriginalMethodSignature(Type[] values)
{
// implementation using values[specificName1] ... values [specificNameN]
}
const int specificName1 = 0;
const int specificName2 = 1;
...
const int specificNameN = n-1;
Is there any way to create an snippet for this purpose? If yes, how would it be?
There isn't any built in way to do what you wan't, because you shouldn't really be doing it at all. You should be using an object with properties instead of an array.
Anyway, you can make an object that encapsulates the array, so that the properties use the array as storage:
public class NamedObject {
private Type[] _values;
public NamedObject(Type[] values) {
_values = values;
}
public SpecificName1 { get { return _values[0]; } set { _values[0] = value; } }
public SpecificName2 { get { return _values[1]; } set { _values[1] = value; } }
public SpecificName3 { get { return _values[2]; } set { _values[2] = value; } }
public SpecificName4 { get { return _values[3]; } set { _values[3] = value; } }
public SpecificName5 { get { return _values[4]; } set { _values[4] = value; } }
public SpecificName6 { get { return _values[5]; } set { _values[5] = value; } }
}
Now you can use the object to access the array:
void OriginalMethodSignature(Type[] values) {
NamedObject obj = new NamedObject(values);
// get a value
Type x = obj.SpecificName4;
// set a value
obj.SpecificName2 = x;
}
Create a dedicated class or struct, and parse the array into it.
public class MyClassOfStuff
{
Type SpecificName1 {get;set;}
Type SpecificName2 {get;set;}
public static MyClassOfStuff Parse(Type[] value)
{
Type specificName1 = values[0];
Type specificName2 = values[1];
...
Type specificNameN = values[n];
}
}
void OriginalMethodSignature(Type[] values)
{
var mystuff = MyClassOfStuff.Parse(values);
}