C# class property getting cached? - c#

I have a class and am setting a UID as a class property because it is used in many methods throughout the program and I don't want to keep having to pass in a value to it. The issue I'm getting is that when I run context.Response.Write(uid) and refresh the page, I get the same value every time.
If I move createRandomString() to context.Response.Write(createRandomString()), I get a new UID every time I reload.
I'm very new to using C# and coming from a PHP background, this is a bit odd for me. I would think that setting a class property would change every load. I'm thinking it probably has something to do with when the program is compiled, the UID is permanently set which still wouldn't make sense.
Code where property is getting set:
public class Emailer : IHttpHandler {
// Define UID
static string uid = createRandomString();
CreateRandomString Code:
public static string createRandomString() {
Guid g = Guid.NewGuid();
string GuidString = Convert.ToBase64String(g.ToByteArray());
GuidString = GuidString.Replace("=", "");
GuidString = GuidString.Replace("+", "");
return GuidString;
}

Static fields are only instansiated once. That is why you always get the same result. Try this...
public class Emailer : IHttpHandler
{
// Define UID
string uid => createRandomString();
}
https://msdn.microsoft.com/en-us/library/aa645751(v=vs.71).aspx

Static class level members with an initialiser are only once the first time any memeber of the class (static or otherwise) is referenced.
The initialisation will only re-run when the assembly the class is contained in is unloaded from memory (e.g. when then executable is unloaded).
For an ASP application the assemblies are loaded and unloaded by the IIS process so you would fund that if you restarted the IIS process (for example) this would cause a new UID to be generated.

Solved it by keeping the fields static but setting the value upon load.
Fields:
// Define UID
static string uid = "";
// Define upload path for files
static string uploadPath = "";
Setting:
// Define UID
uid = createRandomString();
uploadPath = #"c:\" + uid + #"\";

Related

C# deserialize a class - the "default" value of a variable

I save local user settings to xml file. Program contains "Settings" class that serialize when the program is closed and deserialize when it is started next time.
But the problem is that the program is changed all the time, and when I create next version - I want the user settings to be saved. But the program may contains new fields of settings, and then the program will started and deserialised the old xml file - new fields will be null.
Now I check every fields as hard-code in the program, as like:
Settings sts = (Settings)Deserialise(path);
if(sts.Field2 == null) sts.Field2 = "defaultvalue2";
if(sts.Field3 == null) sts.Field3 = "defaultvalue3";
Of course it is not satisfied for me. Is it possible to do "default" value of a variable as the same time when I change code of Settings class? Like this:
class Settings
{
public string Field1 (DefaultValue: "defaultvalue1");
public string Field2 (DefaultValue: "defaultvalue2");
}
public void Main
{
Settings sts = (Settings)Deserialise(path);
foreach(var fld in typeof(sts))
{
if(fld.Value == null)
fld.Value = Settings.Fields[fld].DefaulValue;
}
}
Yes it is possible, simply use the standard way to set standard values:
class Settings
{
public string Field1 = "defaultvalue1";
public string Field2 = "defaultvalue2";
}
public void Main
{
Settings sts = (Settings)Deserialise(path);
/* not needed
foreach(var fld in typeof(sts))
{
if(fld.Value == null)
fld.Value = Settings.Fields[fld].DefaulValue;
}*/
}
https://learn.microsoft.com/zh-tw/dotnet/api/system.xml.serialization.xmlattributes.xmldefaultvalue?view=netcore-3.1
here I google it . maybe try it?
Use default attribute : DefaultValueAttribute
public class Pet
{
// The default value for the Animal field is "Dog".
[DefaultValueAttribute("Dog")]
public string Animal ;
}
The Settings.settings xml file was designed for static project settings and, using user scoped settings, can be saved at runtime. Are you changing the settings so much that it no longer have the 'old' values or just adding to the list of settings?
If just adding, you don't need to loop through the settings one by one and try to guess their types with values as you can just do this:
int myInteger = Properties.Settings.Default.MyIntegerSettingValue;
And writing to the settings file:
Properties.Settings.Default.MyIntegerSettingValue = myInteger;
So if you cannot replace your settings.xml file, my suggestion is to model your settings to a class that contain all of your settings loaded at runtime and for each one missing, just write it out to the Settings file with your default value:
Properties.Settings.Default.MyMissingSetting = "MyDefaultValue"
You can find some nice info on application settings usage here

Change DBase On Run Time C# app

I have developed an accounting program that is working beautifully, but now a new need has arisen.
When I enter the program, by default it reads the DB that I put in the file WinSCM.exe.config and if I want to change I have to exit the program and edit the file changing the DB name.
I did not want it to be this way, because my client does accounting for several companies and each company is a DB, so I wanted a way to select a company and when selecting this company the database is automatically changed in the release version.
I'm using Entity Framework to connect to Sql Server DB
Can someone help me?
I'm not sure what reading your DB is, but normally when you use Entity Framework you create a DbContext object whenever you need to do a query, or at utmost a few queries. You are not supposed to keep this DbContext alive for longer periods of time, say more than a few seconds. A minute would be very rare.
Whenever you create the Dbcontext instance you could use the default constructor that uses the config file to get the connection string to the database.
However one of the other constructors let you define the connection string to the database in the constructor. So if you want to construct your DbContext and connect it to a different database, just use that constructor
If you don't know the connection string, but you have a DbConnection to the database, there will be even a constructor for this case.
Hi Everybody Thank alot for your Answer. I just Solved My Question like this:
Fisrt of all, I created a class wich I called ConnetionTolls with this Content://.
public static class ConnectionTools
{
// all params are optional
public static void ChangeDatabase(
this DbContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
string configConnectionStringName = "")
/* this would be used if the
* connectionString name varied from
* the base EF class name */
{
try
{
// use the const name if it's not null, otherwise
// using the convention of connection string = EF contextname
// grab the type name and we're done
var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
? source.GetType().Name
: configConnectionStringName;
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
// init the sqlbuilder with the full EF connectionstring cargo
var sqlCnxStringBuilder = new SqlConnectionStringBuilder
(entityCnxStringBuilder.ProviderConnectionString);
// only populate parameters with values if added
if (!string.IsNullOrEmpty(initialCatalog))
sqlCnxStringBuilder.InitialCatalog = initialCatalog;
if (!string.IsNullOrEmpty(dataSource))
sqlCnxStringBuilder.DataSource = dataSource;
if (!string.IsNullOrEmpty(userId))
sqlCnxStringBuilder.UserID = userId;
if (!string.IsNullOrEmpty(password))
sqlCnxStringBuilder.Password = password;
// set the integrated security status
sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;
// now flip the properties that were changed
source.Database.Connection.ConnectionString
= sqlCnxStringBuilder.ConnectionString;
}
catch (Exception ex)
{
// set log item if required
}
}
********the way to use it is like this***************
//I use this method in a diferent Class
//This method returns the Entity i use with new connections
public static MyEntities SelectDb(String DataBase,String sqlUser,String pw, String serverInstance){
var selectedDbase = new MyEntities();
// so only reference the changed properties
// using the object parameters by name
selectedDbase.ChangeDatabase
(
initialCatalog: DataBase,
userId: sqlUser,
password: pw,
dataSource: serverInstance// could be ip address 100.23.45.67 etc
);
return selectedDbase;
}
I want to thank everyone here and on other forums because this was the result of Your Contributions

Entity Framework connection string from .DSN file

I have a problem, so I thought I would come to the brightest minds on the web.
I have written an ASP.NET MVC application that interfaces with a web service provided by another application. My app basically just adds some features to the other web application.
Both applications have a database. I am trying to limit the configuration for my application by using the other applications SQL Server credentials. This is so that if they decide to change the password for the other application, mine will just start working.
These credentials are saved in a .DSN file that my application can reach. How can I get my application, which uses Entity Framework, to use a connection string that is created from the details read in the .DSN file?
I can figure out the code to read the .DSN file, so if you wish to provide some code examples you can base them around setting the connection string for EF.
I am also open to other solutions, or even reasons why I shouldn't do this.
Thanks in advance.
PS. As I was writing this, I came up with a little concept. I am going to test it out now to see how it goes. But here is the basics:
On start up, read the needed details into static properties.
public MyContext() : base(getConnectionString()) { }
3.
private SomeObjectTypeHere getConnectionString()
{
//read static properties
//return .....something..... not sure yet....
}
Thoughts on that maybe?
EDIT
I have created a method that reads the .DSN file and gets the server, the user id and the password. I now have these stored in static properties. In my context, how can I set my connection string now that i have the required details.
So, the biggest issue that I was really having was how to set my connection string in Entity Framework. But I was also hoping that maybe someone else had worked with .DSN files.
Anyway, here was my solution. Still looking for problems that might arise from this, so if you can see any issues, let me know!
First, I created a method that was run on startup. This method ran through the .DSN file and picked out the gems.
Keep in mind that I have never worked with .DSN files, and the section that gets the password is unique to my situation.
var DSNFileContents = File.ReadAllLines(WebConfigurationManager.AppSettings["AppPath"] + #"\App.DSN");//reads DSN into a string array
//get UID
string uid = DSNFileContents.Where(line => line.StartsWith("UID")).First().Substring(4);//get UID from array
//test if uid has quotes around it
if (uid[0] == '"' && uid[uid.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
uid = uid.Substring(1, uid.Length - 2);
}
//get server
string server = DSNFileContents.Where(line => line.StartsWith("SERVER")).First().Substring(7);//get the server from the array
//test if server has quotes around it
if (server[0] == '"' && server[server.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
server = server.Substring(1, server.Length - 2);
}
//THIS WON'T WORK 100% FOR ANYONE ELSE. WILL NEED TO BE ADAPTED
//test if PWD is encoded
string password = "";
if (DSNFileContents.Where(line => line.StartsWith("PWD")).First().StartsWith("PWD=/Crypto:"))
{
string secretkey = "<secret>";
string IV = "<alsoSecret>";
byte[] encoded = Convert.FromBase64String(DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(12));
//THIS LINE IN PARTICULAR WILL NOT WORK AS DecodeSQLPassword is a private method I wrote to break the other applications encryption
password = DecodeSQLPassword(encoded, secretkey, IV);
}
else
{
//password was not encrypted
password = DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(4);
}
//build connection string
SqlConnectionStringBuilder cString = new SqlConnectionStringBuilder();
cString.UserID = uid;
cString.Password = password;
cString.InitialCatalog = "mydatabase";
cString.DataSource = server;
cString.ConnectTimeout = 30;
//statProps is a static class that I have created to hold some variables that are used globally so that I don't have to I/O too much.
statProps.ConnectionString = cString.ConnectionString;
Now that I have the connection string saved, I just have my database Context use it as below,
public class myContext : DbContext
{
public myContext() : base(statProps.ConnectionString) { }
//all my DbSets e.g.
public DbSet<Person> Persons{ get; set; }
}
This is simple, yes, but I hoping that it can provide some information to anyone that was looking to do something similar but was not sure about how it should be handled.
Again, let me know if you like or dislike this solution and if you dislike it, what is your solution and why.
Thanks again!

Replace an xml names with a variable

I am working on SharePoint. I have two sites one main site and a sandbox. Their codes are same but xml names of columns are different. So I am trying to make a code in such a all xml names will be replaced by their variables.plzz check my code below.
#if TestSite
public const string context = "url";
public const string Title = "xmlname1";
public const string User_id = "xmlname2";
#else
public const string context = "url2";
public const string Title = "xmlname1";
public const string User_id = "xmlname2";
#endif
when I debug this program it connects to url1....how will I connect it to url2?
Both urls should work for Common code.
It is better to put some kind of identifier in the settings of your program. Then the user can set whether to connect to site A or B.
Sometimes you can use the URL to determine to which system you are connecting, or maybe you can even get the metadata from the service itself, removing the need to keep record of the column names to get. Then you first fetch the metadata, and then actually make the calls to the data endpoints.

How to use enum in AuthorizeAttribute the razor mvc?

I have this enum:
public enum PerfilUsuarioEnum
{
AdministradorSistema = 1,
AdministradorLoja = 2,
Gerente = 3
}
And I want to pass it on my Authorize roles
[Authorize(Roles = PerfilUsuarioEnum.AdministradorLoja + ", " + PerfilUsuarioEnum.Gerente)]
There is some manner to do this?
Roles has to be constant expression such as string. Easiest way is to use cosntant.
public static class PerfilUsuario
{
public const string AdministradorLoja = "AdministradorLoja";
public const string Gerente = "NaviGerentegators";
}
[Authorize(Roles = PerfilUsuario.AdministradorLoja + ", " +
PerfilUsuario.Gerente)]
Great question. Here is what I did...
I decided to make my permissions database driven so I needed a way to convert strings into something "typed" so that I could get compile time warnings and also so I could change the name of the permission in the database and not have to update all of our production code. Since the attributes are string based (so called magic strings), I decided against enumerations and went with a T4 script that read the database and generated a struct for each record. This allowed me to also add things like, a nice display name, details about the permission, and an error message that I could show the user.
Here is a sample permission row after the T4 template runs.
public struct CanViewClaimData
{
// Using const allows the compiler to generate the values in the assembly at compile time and satisfy MVC Authorize Attribute requirements for const strings.
public const System.String Name = "CanViewClaimData";
public const System.String DisplayName = "Can View Claim Data";
public const System.String Description = "The allows users to view claim data";
public const System.String DefaultErrorMessage = "You must have the \"Can View Claim Data\" permission to access this feature.";
}
Then in code I use a sub classed Authorize and mark the Action as such,
[Security.AuthorizedAttribute(Roles = CanViewClaimData.Name, Message = CanViewClaimData.DefaultErrorMessage)]
Then during each automated build and push to our C.I. environment, I run the T4 template as part of the build process to keep the struct strings in sync with the database.
So far this has worked really well and allowed me to give our product owner the ability to edit the permission names, descriptions etc, in the database and without a developer having to be involved.

Categories