When developing ordinary 3T business application you might want to use a custom proxy DLL to access your web service rather then accessing it directly (please do not mix this with proxy DLL generated for you by Visual Studio). If the signature of your proxy DLL is the same as that of your web service you'll be able to swap the two at any given moment. A local DLL will hide the complexity of using web service. In addition to that it is a very good place for implementing client side caching mechanisms for common data (i.e. countries, cities, currencies, etc.); managing retries and emergency procedures; and catching and handling some types of exceptions.
Here's a code fragment showing how you can create simple application proxy with cache mechanism.
class AppProxy
{
private static AppProxy instance;
private DataSet cities;
private DateTime refreshCitiesAt;
public static AppProxy Instance {
get {
if (instance==null)
instance=new AppProxy();
return instance;
}
}
public DataSet ListCities()
{
if (DateTime.Now > refreshCitiesAt)
{
cities=webService.ListCities();
// Refresh in 30 minutes.
refreshCitiesAt = DateTime.Now.AddMinutes(30);
}
return cities;
}
}
And here is how you would call it.
DataSet citiesDs=AppProxy.Instance.ListCities();
Categories patterns
How many times have you stumbled over mess like this?
enum Days { Sat = 1, Sun, Mon, Tue, Wed, Thu, Fri };
private string DayToString(Days day)
{
string str;
switch (day) {
case Days.Mon:
str = "Mon";
break;
case Days.Tue:
str = "Tue";
break;
case Days.Wed:
str = "Wed";
break;
case Days.Thu:
str = "Thu";
break;
case Days.Fri:
str = "Fri";
break;
case Days.Sat:
str = "Sat";
break;
case Days.Sun:
str = "Sun";
break;
default:
str = "Messday";
break;
}
return str;
}
In C++ there was no easy way to cast enumerations to strings and vice versa thus many old dogs keep on using old tricks to do it. However in C# there are several easier ways to achieve the same result. First there is the obvious
Days day = Days.Mon;
dayAsString = day.ToString();
...and it actually works. Then there is a way to retreive string name by index using Enum.GetName function like this...
firstDayOfWeek = Enum.GetName(typeof(Days), 1);
dayAsString = Enum.GetName(typeof(Days),Days.Tue);
There also exists an easy way to cast string back to original enum value by using the Parse function.
Days today = (Days)Enum.Parse(typeof(Days), dayAsString);
Last but not least - for those of you who demand real sophistication - here are casts in both directions via descriptive attributes. The code is somehow sloppy since my objective is to show you how to do it - not do it for you. :)
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.ComponentModel;
public class Warrior
{
private class DescAttrFinder {
private string descAttributeValue;
public DescAttrFinder(string descAttributeValue)
{
this.descAttributeValue = descAttributeValue;
}
public bool FindPredicate(FieldInfo fi)
{
DescriptionAttribute[] descAttributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];
string desc = (descAttributes.Length > 0) ? descAttributes[0].Description : null;
return descAttributeValue.CompareTo(desc) == 0;
}
}
public enum Rank
{
[Description("Private")]
Private = 1,
[Description("Private First Class")]
PrivateFirstClass,
[Description("Specialist")]
Specialist,
[Description("Corporal")]
Corporal,
[Description("Seargant")]
Seargant,
[Description("Staff Sergeant")]
StaffSergeant
}
public string GetRankDescription(Rank rank) {
Type type = typeof(Rank);
FieldInfo fieldInfo = type.GetField(rank.ToString());
DescriptionAttribute[] descAttributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];
return (descAttributes.Length > 0) ? descAttributes[0].Description : null;
}
public Rank GetRankFromDescription(string rank)
{
Type type = typeof(Rank);
List <FieldInfo> fields= new List<FieldInfo>(type.GetFields());
DescAttrFinder finder=new DescAttrFinder(rank);
FieldInfo fi=fields.Find(finder.FindPredicate);
return (Rank)fi.GetRawConstantValue();
}
}
Categories c#
It is a matter of taste and as old Roman wisdom teaches de gustibus non est dispudandum. I use this.
1 /*
2 * $Workfile: $
3 *
4 * This file contains implementation of xxxxxxxx class.
5 *
6 * Note:
7 *
8 * (C) Copyright 2007 My Company Ltd.
9 * All rights reserved.
10 *
11 * $Revision: $
12 *
13 * $Log: $
14 *
15 */
It includes source control tags which are standard and supported by most source control systems.
If you plan to use this you should really include it into your Visual Studio new file template so that you don't have to copy'n'paste it every time you create a new class.
Today’s article is about performance issues of using guids as primary keys in your SQL tables.
Some time ago I did tests to figure out what performance penalty of using guids as primary keys would be. I tested insert and select statements on 10.000, 50.000, 200.000 and 1.000.000 records. If your problem is larger you will have to do your own measurements.
Here are my conclusions.
For select statements performance penalty is linear and can be ignored.
For insert statements it is different. Performance penalty grows exponentially. Following is the graph showing my test results.
I assume that generating new guid requires much more math then simply increasing integer by one. Writing 16 bytes is more expensive then writing 4.
Conclusion: it makes sense avoiding guids as primary keys if performance of insert statements is critical to your system.
Categories sql
But of course.
SELECT NewId()
You may also use NewId function as a default value of uniqueidentifier field type in a table definition. Just add it to your create table statement like this:
[MyField] [uniqueidentifier] NOT NULL DEFAULT (NewId())
Categories sql
Sometimes you will display search mask to your user. The user will then enter search conditions. You will return a list of all records matching them; unless conditions were left empty in which case you will ignore them.
Today's article deals with the SQL part of this problem.
One approach that I've seen many times is to generate SQL on the fly and use sp_executesql to execute it. But this should really be avoided because it breaks SQL Server's chained security.
Much more elegant solution is to use simple or clause in the where statement. Following code demonstrates how to do it.
1 CREATE PROCEDURE ListPersons
2 @Name AS VARCHAR(30) = NULL
3 ,@DOBFrom AS DATETIME = NULL
4 ,@DOBTo AS DATETIME = NULL
5 AS
6 SELECT
7 FirstName
8 ,LastName
9 ,DOB
10 FROM
11 Person P
12 WHERE
13 (P.Name LIKE ‘%’+ @Name +’%’ OR @Name IS NULL)
14 AND (P.DOB >= @DOBFrom OR @DOBFrom IS NULL)
15 AND (P.DOB <= @DOBTo OR @DOBTo IS NULL)
There. Calling ListPersons without parameters will return all persons. Calling ListPerson with only DOBFrom parameter will return all persons that have date of birth larger or equal to this parameter. Any additional parameter will narrow down your search.
Categories sql