Anders Ivner
Tuesday, August 7, 2012
How to handle Microsoft.mshtml.dll
It is distributed with Visual Studio, and installed to the GAC, which is why this issue will often not be descovered until you deploy.
This is how I handle the issue.
First, copy the dll to the 'imports' folder in your souce control tree. (You should do this with all your dependencies anyway). This will ensure that it can be found on any other machine, such as a build server, which may not have VS installed.
Then, when you add a reference to the dll, be sure to browse to the import location. In the properties of the reference, set 'Embed Interop Types' to False and 'Copy Local' to True. This will copy the dll to the output directory, so that it will be available, and not have to be separately installed on client machines.
Thursday, May 19, 2011
Tip of the day: Reload your static or semistatic data continuously.
Ok, so maybe there is some sort of script that was used to initially load the data. And when a change is necessary, such as when you need to add more dates or change the fiscal calendar, you can patch the script and reapply it, right?
Then, after a few rounds of patching by various developers, the data starts to look slightly inconsistent, and it's no longer apparent where the different fields come from. Maybe someone patched the data without commiting his script changes to source control.
The only way to avoid the risk of someone patching the static data by hand is to continuously reload it from a script. And by continuously I mean at least daily. That way, if you need to change the data, you have to change the script. And you don't have to wonder which script was used to load the data, because you can be 100% certain that it was the script that ran last night. And every night before that.
From a technical standpoint, you typically cannot delete the data and then reinsert it, as you'll have referential integrity contraints that would break, and it wouldn't be a good idea anyway to risk getting different PKs. What I do instead is I first insert any missing rows (with null or default values for non-pk columns), and then do an update on the whole table, setting not just the columns for the new rows, but for every row in the table.
If you cannot reload your data, it is at risk of being corrupted. And the only way to know that you can, is to do.
Monday, August 31, 2009
Calling stored procedures using .net lambda expression trees
Calling stored procedures from ADO.Net leads to verbose code with lots of syntactic overhead. It tends to look something like this:
comm.CommandType = CommandType.StoredProcedure;
comm.Parameters.Add(new SqlParameter()
{
ParameterName = "@return",
Direction = ParameterDirection.ReturnValue,
DbType = DbType.Int32
});
comm.Parameters.Add(new SqlParameter("@param1", 17));
comm.Parameters.Add(new SqlParameter()
{
ParameterName = "@outparam",
Direction = ParameterDirection.Output,
DbType = DbType.String,
Size = -1
});
comm.ExecuteNonQuery();
And all this to represent a call more succinctly written as:
result = MySProc 17, out outparam
We can achieve something close to this in C#, using lambda expression trees. Assuming that we will use a static method, and that we also need to pass in a connection, our call will look like:
StoredProcedures.Exec(
() => MySProc(17, out outparamvalue),
connection);
For this to work, we will start by specifying the signature of the stored procedure with a normal .net method. Like so:
public int MySProc(int param1, out string outparam)
{
}
and so, the signature for our Exec-method becomes:
public static int Exec(Expression<Func<int>> expr,
SqlConnection conn)
The Expression<> thing is what causes the compiler to stop doing what it normally does, which is to compile C# into MSIL, and instead give you the expression tree.
Focusing on the interesting bits, and leaving the details for the full code sample at the end, we start by noting that we are only interested in expressions that are method calls:
var callExpr = (MethodCallExpression)expr.Body;
The method name is simply callExpr.Method.Name. On to find the arguments!
foreach (var arg in callExpr.Arguments)
The arguments are themselves expressions, and that’s not really what we want right now. Although “17” in our example would be easy enough to handle, this really could be an arbitrarily complex expression. Thankfully, .Net lets us compile lambda expressions into delegates that we can then call to get the value of the expression. There are two minor details to get this working: First, the expression is strongly typed (as e.g. integer) and we need the boxed value, so we wrap the expression in a cast to object. Second, we create a lambda expression with our expression as the body. The type of the lambda expression is a function taking no arguments and returning an object. The code is:
private static object GetValue(Expression expr)
{
var valueExpr = Expression.Lambda<Func<object>>(
Expression.Convert(expr, typeof(object)),
new ParameterExpression[] { });
var deleg = valueExpr.Compile();
return deleg();
}
A bit more of a problem is handling out parameters. The argument – outparamvalue in our example above – is (typically) a local variable in the calling method. How do we assign a value to that? We need to look deeper into how the C# compiler treats anonymous methods. While this topic is worthy of a blog post of its own, the following brief summary will have to do: The compiler creates a class for the anonymous method, and the local variables become fields on that class. Thus, the out parameter expression becomes a field reference.
With that in mind, we can find the field and assign it using reflection:
private static void SetValue(Expression outarg, object value)
{
var member = (MemberExpression)outarg;
object source = GetValue(member.Expression);
var field = (FieldInfo)member.Member;
field.SetValue(source, value);
}
And we are done. The full code, as promised, is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
namespace StoredProcedureCaller
{
public class StoredProcedures
{
private static object GetValue(Expression expr)
{
var valueExpr = Expression.Lambda<Func<object>>(
Expression.Convert(expr, typeof(object)),
new ParameterExpression[] { });
var deleg = valueExpr.Compile();
return deleg();
}
private static void SetValue(Expression outarg, object value)
{
var member = (MemberExpression)outarg;
object source = GetValue(member.Expression);
var field = (FieldInfo)member.Member;
field.SetValue(source, value);
}
private static object ConvertToDbValue(object val)
{
if (val == null)
return DBNull.Value;
else
return val;
}
private static object ConvertFromDbValue(object val)
{
if (val == DBNull.Value)
return null;
else
return val;
}
public static int Exec(Expression<Func<int>> expr,
SqlConnection conn)
{
if (expr.Body.NodeType != ExpressionType.Call)
throw new ArgumentException("StoredProcedures.Exec() can only be used on method calls");
var callExpr = (MethodCallExpression)expr.Body;
var command = new SqlCommand(){
CommandText = callExpr.Method.Name,
CommandType = System.Data.CommandType.StoredProcedure,
Connection = conn
};
command.Parameters.Add(new SqlParameter()
{
ParameterName = "@return",
DbType = DbType.Int32,
Direction = ParameterDirection.ReturnValue
});
var paramlist = callExpr.Method.GetParameters();
var i = 0;
foreach (var arg in callExpr.Arguments)
{
var param = paramlist[i];
var sqlparam = new SqlParameter();
sqlparam.ParameterName = "@" + param.Name;
if (param.IsOut)
{
sqlparam.Direction = ParameterDirection.Output;
sqlparam.Size = -1;
}
else
{
sqlparam.Direction = ParameterDirection.Input;
sqlparam.Value = ConvertToDbValue(GetValue(arg));
}
command.Parameters.Add(sqlparam);
i++;
}
command.ExecuteNonQuery();
i = 1;
foreach (var arg in callExpr.Arguments)
{
var sqlparam = command.Parameters[i];
if (sqlparam.Direction == ParameterDirection.Output)
SetValue(arg, ConvertFromDbValue(sqlparam.Value));
i++;
}
return (int)command.Parameters[0].Value;
}
}
}
Sunday, June 7, 2009
Asynchronously calling an SSIS package from ASP.Net
Monday, September 29, 2008
Do-not-break-the-testcases 101
Friday, September 5, 2008
Chrome
Wednesday, May 7, 2008
Nullable enums
public enum Foo { X, Y };
[...]
public Foo Bar { set { ... } }
[...]
PropertyInfo prop = obj.GetType().GetProperty("Bar");
prop.SetValue(obj, (object)1, null);
I.e. you can use reflection to set the value of a property of an enum type using its integer value. (You could also just cast it like so: obj.Bar = (Foo)1;, but that's not quite as interesting, for reasons that will be revealed later.)
Also, a boxed value and a boxed nullable value have the same representation, right? They are both pointers to a small object containing the primitive. As the following code shows, boxed integers and boxed nullable integers are interchangeable:
int intValue = 1;
int? nullableIntValue = 1;
object boxedInt = intValue;
object boxedNullableInt = nullableIntValue;
intValue = (int)boxedNullableInt;
nullableIntValue = (int?)boxedInt;
And, not surprisingly, the same holds for enum values, now demonstrated using reflection as in our first example:
public Foo? Bar { set { ... } }
[...]
prop.SetValue(obj, (object)Foo.X, null);
Now, combining these two examples, what do you think the following code would do?
public Foo? Bar { set { ... } }
[...]
prop.SetValue(obj, (object)1, null);
If you, like me, thought it would happily set the property to the enum value correspoding to 1, in this case Foo.X, you'd be wrong. Instead it throws the following exception:
Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1
Huh? The .net designers may know why this is, and they may even have a good reason for it, but to me it just seems plain weird. It is worth noting that obj.Bar = (Foo?)1; works just fine.
This issue came up when mapping objects from database tables, using integers to represent enum values. I've reluctantly added the following workaround to my mapping code:
PropertyInfo prop = [...]
object val = [...]
if ((prop.PropertyType.IsGenericType) &&
(prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
Type targetType = prop.PropertyType.GetGenericArguments()[0];
if (targetType.IsEnum)
val = Enum.ToObject(targetType, val);
}
prop.SetValue(obj, val, null);