I found this little snippet on a blog by Mark Wagner's blog,
and already this baby has saved me quite a bit of work, so I thought I'd post it also, btw. Marks blog can be found here
Convert a string to an enumerated (enum) value.
Using the Enum.Parse method, you can easily convert a string value to an enumerated value. Doing this requires the type of the enum and string value. Adding the true argument will cause the case to be ignored.
Using the following enum for this example:
private enum Aircraft
{
Beech,
Cessna,
Piper
}
You can easily convert the string to an enum value like this:
Aircraft air = (Aircraft) Enum.Parse(typeof(Aircraft), "Cessna", true);
Ideally you should wrap a try-catch around the Enum.Parse statement.
Thursday, June 22, 2006
Saturday, May 27, 2006
watching for changes in webapps
Recently I came across code in a project that had been built to check for changes in order to give the user warnings like "remember to save.." "do you really want to navigate away.." etc. As this project uses Typed datasets for all they're worth (which is quite a lot as long as the complexity of the domain is easily managed) the actual check for changes was done through calling the datasets ToXml() method and holding that string in the session and constantly check against that as the user went about his business.
Now, this project had in NO way a stateless web server, but then the requirements didn't call for that either, but still. each dataset (of which the user would typically have 1-20 of within a session) was saved in the session and also its xml was saved (to perform change-watching).
Thw problem was that although there were few users (<10), the xml for each dataset had a footprint of about 1.6 MB each.
So what did I do to ease the pain? I changed the code to check and save not the raw xml, but a hash of the xml. To do this I made one small method that translated from string to a hashed string, All up I spent about 20 minutes implementing and testing this schema and the estimated footprint-savings is in the area of 150 MB of server memory.
so what about the code eh? well here it is:
public static string ComputeHashFromString(string message, HashAlgorithm ha)
{
byte[] msgbytes = ASCIIEncoding.ASCII.GetBytes(message);
byte[] hashBytes = ha.ComputeHash(msgbytes);
StringBuilder sb = new StringBuilder();
foreach(byte b in hashBytes)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
public static string ComputeHashFromString(string message)
{
return ComputeHashFromString(message, new MD5CryptoServiceProvider());
}
Now, this project had in NO way a stateless web server, but then the requirements didn't call for that either, but still. each dataset (of which the user would typically have 1-20 of within a session) was saved in the session and also its xml was saved (to perform change-watching).
Thw problem was that although there were few users (<10), the xml for each dataset had a footprint of about 1.6 MB each.
So what did I do to ease the pain? I changed the code to check and save not the raw xml, but a hash of the xml. To do this I made one small method that translated from string to a hashed string, All up I spent about 20 minutes implementing and testing this schema and the estimated footprint-savings is in the area of 150 MB of server memory.
so what about the code eh? well here it is:
public static string ComputeHashFromString(string message, HashAlgorithm ha)
{
byte[] msgbytes = ASCIIEncoding.ASCII.GetBytes(message);
byte[] hashBytes = ha.ComputeHash(msgbytes);
StringBuilder sb = new StringBuilder();
foreach(byte b in hashBytes)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
public static string ComputeHashFromString(string message)
{
return ComputeHashFromString(message, new MD5CryptoServiceProvider());
}
Tuesday, May 16, 2006
Making Custom Properties aware of their context in EPiServer
What you might want to do inside a custom property is to check the value of some other properties in the current page. What you will notice is that Custom Properties are not aware of the CurrentPage, in order to fetch it you will need to override the
InitializeData method that the base class of all EPiServer properties has.
You can get the pagereference within that method
PageReference _pageLink;
public override void InitializeData(EPiServer.ApplicationConfiguration config,PropertyDataCollection properties)
{
PropertyPageReference pageLinkProperty = properties["PageLink"] as PropertyPageReference;
if (!pageLinkProperty.IsNull) { _pageLink = pageLinkProperty.PageLink;}
base.InitializeData(config, properties);
}
InitializeData method that the base class of all EPiServer properties has.
You can get the pagereference within that method
PageReference _pageLink;
public override void InitializeData(EPiServer.ApplicationConfiguration config,PropertyDataCollection properties)
{
PropertyPageReference pageLinkProperty = properties["PageLink"] as PropertyPageReference;
if (!pageLinkProperty.IsNull) { _pageLink = pageLinkProperty.PageLink;}
base.InitializeData(config, properties);
}
Wednesday, April 26, 2006
Report Server: The report server cannot decrypt the symmetric key
If you ever come across this error message in SQL Server 2000 Report Server, it is usually caused by one of two things. Either you have recently changed the account that is used to run the ReportServer service, in which case you should follow this article:
http://support.microsoft.com/kb/842421
or you installed or uninstalled some part of .net 2.0 recently, in which case you might have to run the rsactivate tool. go to the directory:
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting
Services\ReportServer\
or the equivalent program path on your computer and type
rsactivate -r -c RSReportServer.config
if rsactivate is not in your path (which it should be after an install) you will find it in
C:\Program Files\Microsoft SQL Server\80\Tools\Binn
or whatever path is the equivalent on your machine
http://support.microsoft.com/kb/842421
or you installed or uninstalled some part of .net 2.0 recently, in which case you might have to run the rsactivate tool. go to the directory:
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting
Services\ReportServer\
or the equivalent program path on your computer and type
rsactivate -r -c RSReportServer.config
if rsactivate is not in your path (which it should be after an install) you will find it in
C:\Program Files\Microsoft SQL Server\80\Tools\Binn
or whatever path is the equivalent on your machine
Wednesday, March 22, 2006
Thinking Ruby in C# 2.0 ?
foreach(string chosenstring in myList.FindAll(new Predicate<string>(delegate(string s)
{
return s.Length>10;
})))
{
Console.WriteLine("the following string is long: " +chosenstring);
}
The preceding code will run through a list containing strings and output the strings longer than 10 words.
read it and weep
{
return s.Length>10;
})))
{
Console.WriteLine("the following string is long: " +chosenstring);
}
The preceding code will run through a list containing strings and output the strings longer than 10 words.
read it and weep
Friday, March 03, 2006
Setting asp:Label texts too early
Just discovered that if you have method calls to the code-behind (typically a protected method in the codebehind called between <% %> tags) You cannot alter The text property on labels in that method.
This probably extends to manipulating any property on any webcontrol defined in the code-front. I guess it's just too early.
when stepping through the code The label had its original value (which obviously would have been read/instantiated in the code-front), I replaced it with a new value and when the page rendered it had turned back to the original value.
I guess this means that the code-front is read twice, before method calls in it are handled, and after. Is it just me that find this weird?
The fix to my problem was easy, I just placed the method-call in Page_Load, so no biggie, but I was stumped on it for a while
Edit: OK, so I might have missed the obvious, but of course the ViewState is copied back.. and overwrites my changes. Since ViewState is copied just before Page_Load, The earliest you can write to weeb-controls is page_load
This probably extends to manipulating any property on any webcontrol defined in the code-front. I guess it's just too early.
when stepping through the code The label had its original value (which obviously would have been read/instantiated in the code-front), I replaced it with a new value and when the page rendered it had turned back to the original value.
I guess this means that the code-front is read twice, before method calls in it are handled, and after. Is it just me that find this weird?
The fix to my problem was easy, I just placed the method-call in Page_Load, so no biggie, but I was stumped on it for a while
Edit: OK, so I might have missed the obvious, but of course the ViewState is copied back.. and overwrites my changes. Since ViewState is copied just before Page_Load, The earliest you can write to weeb-controls is page_load
Sunday, February 26, 2006
VS2003: "unable to read the project file" "the system cannot find the file specified"
OK, so I've had this nuissance for a week before I finally snapped and had to fix it: Every time I started Visual Studio and opened up my project I would get an error message saying something to the effect of "unable to read the project file" "the system cannot find the file specified"...
The web project would not be loaded, only be displayed as "unavailable" and any project with bindings to the web project (IE. the test project) would lose their bindings.
The drill would be to delete the unavailable project and add it anew through file -> add project -> from file. This would then fix the problem temporarily, except I would need to set the lost bindings again.
If I tried to add the project from web I would get the error message stated above.
So how does one solve such a predicament?
Exit VS,
Delete the .SUO file
Start VS
Set the source control that you lost
Done, enjoy error free heaven
The web project would not be loaded, only be displayed as "unavailable" and any project with bindings to the web project (IE. the test project) would lose their bindings.
The drill would be to delete the unavailable project and add it anew through file -> add project -> from file. This would then fix the problem temporarily, except I would need to set the lost bindings again.
If I tried to add the project from web I would get the error message stated above.
So how does one solve such a predicament?
Exit VS,
Delete the .SUO file
Start VS
Set the source control that you lost
Done, enjoy error free heaven
Thursday, January 05, 2006
OK so I blew it
I ran out of steam mid-december, I tried to find other stuff i wanted to share with the world of programmers out there, I really really had heaps of stuff to do at work. and suddenly I needed to get xmas prezzies for everyone... jeez get off my back will you?
Basicly I figured out that instead of writing twelve more posts that weren't interesting I'd take some time out and figure out new stuff to write about so that the quality of the blog wouldn't plummet.
To all would-be christmas calendar writers out there: do yourselves a favor, have the calendar ready before december, coz december isn't as slow and easy as one would like to think.
So instead of sweating it, I'll write when I want about what I want.
So there
Basicly I figured out that instead of writing twelve more posts that weren't interesting I'd take some time out and figure out new stuff to write about so that the quality of the blog wouldn't plummet.
To all would-be christmas calendar writers out there: do yourselves a favor, have the calendar ready before december, coz december isn't as slow and easy as one would like to think.
So instead of sweating it, I'll write when I want about what I want.
So there
Thursday, December 15, 2005
Christmas Calendar 11/24
This one goes out to all non-americans
As we all know, dates should be represented on the format
dd.mm.yyyy - or derivatives thereof.
NOT
mm.dd.yyyy
so here is the case: Sql Server 2000 will, in its
Enterprise Manager, display all dates on the format
as defined by the regional settings of the local user
looking at the database.
both the Database and the Sql Server has settings for locale and
language etc. but they are all overridden by the locale of the user.
keep this in mind when, oh say, remoting into a server using some
admin user to do stuff on the DB through E.M.
You might just be editing dates the "wrong" way
As we all know, dates should be represented on the format
dd.mm.yyyy - or derivatives thereof.
NOT
mm.dd.yyyy
so here is the case: Sql Server 2000 will, in its
Enterprise Manager, display all dates on the format
as defined by the regional settings of the local user
looking at the database.
both the Database and the Sql Server has settings for locale and
language etc. but they are all overridden by the locale of the user.
keep this in mind when, oh say, remoting into a server using some
admin user to do stuff on the DB through E.M.
You might just be editing dates the "wrong" way
Monday, December 12, 2005
Christmas Calendar 12/24
In javascript the "enabled" property is instead called the "disabled" property with opposite effect. How curius! Does this point at some underlying mentality on the part of the JS developers?
Saturday, December 10, 2005
Christmas Calendar 10/24
Array casting.
I have stumped on this one in the past:
Why can't I cast an array of one type to an array of another type?.
I fill my ArrayList with nothing but strings, I need to pass the content as a simple string-array (maybe in conjuncture with some web-service).
I call the ToArray(typeof(string)) on the arrayList and we should be done....
.. almost anyway, I also have to typecast the Array returned into the string[]
string[] stringArray = (string[])stringList.ToArray(typeof(string));
ok, this works.. but what if my strings are already contained in a object array, such as would be returned from a call to the simple ToArray() function on ArrayList.
would this work?
object[] object_array = stringList.ToArray();
string[] string_array = (string[]) object_array;
sounds simple? well it is, .. it is too simple, so simple, in fact, that it won't work. You can't bulk-cast an array and all of its content in one go.
(but wait, didn't we just do that above? .... no we didn't. The content was already cast into the correct form. That's how come even though we supplied the object type we still only got a generic Array back the generic Arrays content was correct. only the shell was needed to be explicitly cast into the correct form)
so. what to do eh?
do we have to settle for the old an known?
for(int i = 0; i<object_array.Length; i++)
{
string[i] = (string)object[i];
}
not bloody likely! Let's instead use the Array.CopyTo() function!
string[] string_array = new string[object_array.Length];
object_array.CopyTo(string_array, 0);
so there's two ways of array-cast
Merry xmas to everyone :)
I have stumped on this one in the past:
Why can't I cast an array of one type to an array of another type?.
I fill my ArrayList with nothing but strings, I need to pass the content as a simple string-array (maybe in conjuncture with some web-service).
I call the ToArray(typeof(string)) on the arrayList and we should be done....
.. almost anyway, I also have to typecast the Array returned into the string[]
string[] stringArray = (string[])stringList.ToArray(typeof(string));
ok, this works.. but what if my strings are already contained in a object array, such as would be returned from a call to the simple ToArray() function on ArrayList.
would this work?
object[] object_array = stringList.ToArray();
string[] string_array = (string[]) object_array;
sounds simple? well it is, .. it is too simple, so simple, in fact, that it won't work. You can't bulk-cast an array and all of its content in one go.
(but wait, didn't we just do that above? .... no we didn't. The content was already cast into the correct form. That's how come even though we supplied the object type we still only got a generic Array back the generic Arrays content was correct. only the shell was needed to be explicitly cast into the correct form)
so. what to do eh?
do we have to settle for the old an known?
for(int i = 0; i<object_array.Length; i++)
{
string[i] = (string)object[i];
}
not bloody likely! Let's instead use the Array.CopyTo() function!
string[] string_array = new string[object_array.Length];
object_array.CopyTo(string_array, 0);
so there's two ways of array-cast
Merry xmas to everyone :)
Friday, December 09, 2005
Christmas Calendar 9/24
Why don't my 3.rd party DLL come along to play on my deployment server when I choose "Copy Project" on my web solution?
If your web solution is layered into different projects with a separate DLL for, say, business logic. If your BL project needs DLLs, you need to put them into the web project Lib folder, add them to the project and reference them from the web-project. This way they will play along nicely!
If your web solution is layered into different projects with a separate DLL for, say, business logic. If your BL project needs DLLs, you need to put them into the web project Lib folder, add them to the project and reference them from the web-project. This way they will play along nicely!
Thursday, December 08, 2005
Christmas Calendar 8/24
What to do when you want to bind more than one field into a dropdownlist?
You've created your object,
BEHOLD MY BEAUTIFUL OBJECT "MyObject" !!!
and you want a Dropdown to contain, say, both the Id property and the Name property.
"DOH" you might say, now I've got to create a new property that contains the textual representation of the Id and Name in the object.. "why oh why must my beautiful object depend on the whims of my presentation layer"
fear not ye brave coders. the solution is nigh!
write one of these beauts and you'll be set.
DropDownList1.DataTextField = MyObject.Id & ”-” & MyObject.Name;
DropDownList1.DataValueField = MyObject.Id;
DropDownList1.DataBind();
The & is not to be confused with && as in "logical AND". but is more like "AND concatenate THIS!! "
You've created your object,
BEHOLD MY BEAUTIFUL OBJECT "MyObject" !!!
and you want a Dropdown to contain, say, both the Id property and the Name property.
"DOH" you might say, now I've got to create a new property that contains the textual representation of the Id and Name in the object.. "why oh why must my beautiful object depend on the whims of my presentation layer"
fear not ye brave coders. the solution is nigh!
write one of these beauts and you'll be set.
DropDownList1.DataTextField = MyObject.Id & ”-” & MyObject.Name;
DropDownList1.DataValueField = MyObject.Id;
DropDownList1.DataBind();
The & is not to be confused with && as in "logical AND". but is more like "AND concatenate THIS!! "
Wednesday, December 07, 2005
Christmas Calendar 7/24
Say you need to get the last version before some point in time of a record from a DB that stores multiple versions of the same data timestamps, what would be the most efficient way?
After testing a few things we arrived on this little beauty, simple yet effective.
select * from tblMyTable a
WHERE not exists
( select 1 from tblMyTable a1
where a1.version > a.version and a1.id = a.id and a1.version <= @pointInTime )
and a.version <= @pointInTime )
A trap one might blunder into is not narrowing the outer query by @pointInTime which would give you too many records back
After testing a few things we arrived on this little beauty, simple yet effective.
select * from tblMyTable a
WHERE not exists
( select 1 from tblMyTable a1
where a1.version > a.version and a1.id = a.id and a1.version <= @pointInTime )
and a.version <= @pointInTime )
A trap one might blunder into is not narrowing the outer query by @pointInTime which would give you too many records back
Tuesday, December 06, 2005
Happy happy joy joy
A: I would like to congratulate myself on passing on Microsoft certification exam 70-300 (.Net Architect)
A: Thanks Andreas! That's so nice of you! But how did you know?
A: Coz you just won't shut up about it.
A: Aahh. That'd explain it!
A: Thanks Andreas! That's so nice of you! But how did you know?
A: Coz you just won't shut up about it.
A: Aahh. That'd explain it!
Christmas Calendar 6/24
Never ever ever ever ever ever ever ever ever ever ever ever ever ever
declare Enums / constants in the business layer of an application (or any other conventional layer for that sake).
Before you know it you will need to access those from a layer that doesn't have access to the business layer, and then my friend you are screwed.
Put them instead in a util - project that is included into every other project, that way you won't have to use sql like "where ProjectStatusId = 23" in your dataaccess-code.
The same goes for accessing application configuration settings. Write the code once in a util-project and walk away knowing that it's there.
"but why not just put this stuff into the domain model" - you ask...
1) because Andreas says so
2) because more stuff gets configured through config settings and constants than just domain logic. keep it clean and DRY!.. take it out into a separate (small and cute) util-project
how does the lyrics to that song lyric go?
--"you got to keep 'em separated .. *DÆNH DÆNH DÆNH DÆNH"
declare Enums / constants in the business layer of an application (or any other conventional layer for that sake).
Before you know it you will need to access those from a layer that doesn't have access to the business layer, and then my friend you are screwed.
Put them instead in a util - project that is included into every other project, that way you won't have to use sql like "where ProjectStatusId = 23" in your dataaccess-code.
The same goes for accessing application configuration settings. Write the code once in a util-project and walk away knowing that it's there.
"but why not just put this stuff into the domain model" - you ask...
1) because Andreas says so
2) because more stuff gets configured through config settings and constants than just domain logic. keep it clean and DRY!.. take it out into a separate (small and cute) util-project
how does the lyrics to that song lyric go?
--"you got to keep 'em separated .. *DÆNH DÆNH DÆNH DÆNH"
Monday, December 05, 2005
Christmas Calendar 5/24
A quick one today:
If you want controls in datagrids to be available in the viewstate, they must be declared and initialised within the page_init. If you want access to calculated values in the footer of a datagrid, you need to make sure the controls containing those values are initialised in page_init or you're screwed.
This is a result of the TrackViewState method on DataGrids being called just before the Load event is fired. The TrackViewState method does exactly what you would expect, it tracks the viewstate, ie. it puts all its controls into the ViewState
If you want controls in datagrids to be available in the viewstate, they must be declared and initialised within the page_init. If you want access to calculated values in the footer of a datagrid, you need to make sure the controls containing those values are initialised in page_init or you're screwed.
This is a result of the TrackViewState method on DataGrids being called just before the Load event is fired. The TrackViewState method does exactly what you would expect, it tracks the viewstate, ie. it puts all its controls into the ViewState
Sunday, December 04, 2005
Christmas Calendar 4/24
When working in .Net, you might wonder why it doesn't round off numbers the same way you learned in school.
.Net uses what is called "Bankers rounding" which means that in the event of a tie (e.g. 2,5) it will round towards the nearest even number, so
Math.Round(2.5) --> 2
Math.Round(1.5) --> 2
This is due to the fact that consistently rounding up (as you might remember from your schooldays) will result in a strictly increasing rounding error for all "tied" numbers (.5). Since banks typically have quite a few transactions each day, the term "strictly increasing rounding error" sounds bad to them.
why does .Net provide this rounding as default? -dont know dont care
what do we do about it? - do know do care:
define and use MidpointRounding.AwayFromZero as parameter in a custom util method.
public enum MidpointRounding
{
ToEven, AwayFromZero
}
public class Util
{
public static double Round( double number, int digits, MidpointRounding roundingType)
{
if (roundingType == MidpointRounding.AwayFromZero)
{
double multiplyValue = Math.Pow( 10, digits );
double dRound = Math.Floor(((number*2*multiplyValue)+1)/2)/multiplyValue;
return dRound;
}
else
{
return Math.Round(number,digits);
}
}
}
.Net uses what is called "Bankers rounding" which means that in the event of a tie (e.g. 2,5) it will round towards the nearest even number, so
Math.Round(2.5) --> 2
Math.Round(1.5) --> 2
This is due to the fact that consistently rounding up (as you might remember from your schooldays) will result in a strictly increasing rounding error for all "tied" numbers (.5). Since banks typically have quite a few transactions each day, the term "strictly increasing rounding error" sounds bad to them.
why does .Net provide this rounding as default? -dont know dont care
what do we do about it? - do know do care:
define and use MidpointRounding.AwayFromZero as parameter in a custom util method.
public enum MidpointRounding
{
ToEven, AwayFromZero
}
public class Util
{
public static double Round( double number, int digits, MidpointRounding roundingType)
{
if (roundingType == MidpointRounding.AwayFromZero)
{
double multiplyValue = Math.Pow( 10, digits );
double dRound = Math.Floor(((number*2*multiplyValue)+1)/2)/multiplyValue;
return dRound;
}
else
{
return Math.Round(number,digits);
}
}
}
Saturday, December 03, 2005
Christmas Calendar 3/24
Modulus operator (%)
It might be obvious to some, especially those who hva studied maths (and remember the curriculum) that the modulus operator can return negative values.
The modulus operator will return an answer within 0 +- n
For instance: 13 % 10 = 3
but -13 % 10 = -3
This is different from for example ruby's implementation that will return 7 on that same query. try it yourself.
if you want (imho) logical modulus, write your own util-method:
public static int Mod(int i, int n){
return (((i % n) + n) % n)
}
Thanks to Erlend W. Oftedal for help on this post
It might be obvious to some, especially those who hva studied maths (and remember the curriculum) that the modulus operator can return negative values.
The modulus operator will return an answer within 0 +- n
For instance: 13 % 10 = 3
but -13 % 10 = -3
This is different from for example ruby's implementation that will return 7 on that same query. try it yourself.
if you want (imho) logical modulus, write your own util-method:
public static int Mod(int i, int n){
return (((i % n) + n) % n)
}
Thanks to Erlend W. Oftedal for help on this post
Friday, December 02, 2005
Christmas Calendar 2/24
Iterating enums
it's not trivial to iterate enums in .Net 1.1
A solution is to do the following (iterating MyEnum):
foreach(string enumstring in Enum.GetNames(typeof(MyEnum)))
{
MyEnum enumItem = Enum.Parse(typeof(MyEnum),enumstring);
...
}
This will only work if the enum has a different GetHashCode() for all the
items in it. Otherwise only the first item with a given hashcode will be used (multiple times).
This is due to the ridicoulus fact that Enum.Parse does not match the name given with the enum's ToString (as one would expect) but rather matches on the hashcodes...
go figure!
it's not trivial to iterate enums in .Net 1.1
A solution is to do the following (iterating MyEnum):
foreach(string enumstring in Enum.GetNames(typeof(MyEnum)))
{
MyEnum enumItem = Enum.Parse(typeof(MyEnum),enumstring);
...
}
This will only work if the enum has a different GetHashCode() for all the
items in it. Otherwise only the first item with a given hashcode will be used (multiple times).
This is due to the ridicoulus fact that Enum.Parse does not match the name given with the enum's ToString (as one would expect) but rather matches on the hashcodes...
go figure!
Subscribe to:
Posts (Atom)
