Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Monday, December 04, 2017

Advent of Code 2017 - SmartyStreets Sponsor Text

I just learned about the Advent of Code -- an event with a new short, fun programming puzzle published in each of the 24 days leading up to Christmas.

I noticed that primary event sponsor SmartyStreets has some cryptic text as their sponsor comment:

U2VuZGluZyBDaH Jpc3RtYXMgY2Fy ZHMgdG8gYmFkIG FkZHJlc3Nlcz8K

I won't spoil what it says here, but the only hint you should need to decode the text is that it is base64 encoded. (Also, automatic base64 decoder websites are readily available!)

Also, I'm publishing my C# Advent of Code 2017 solutions on GitHub. I'm generally aiming to optimize them for readability, rather than for minimum lines of code or fastest possible execution speed -- which is what I generally do as well when writing actual production code.  That being said, I have been pretty blown away by the impressive brevity of the solutions of some of the event leaderboard's top members!

Wednesday, August 10, 2016

Bulk upsert into SQL Server

I recently worked through a situation where a bulk upsert (update if a matching record already exists; otherwise insert a new record) to SQL Server implemented using Entity Framework 6 was producing the correct results, but running very slowly. 

I was able to improve the performance of the bulk upsert by about 600x (!!!) by replacing the Entity Framework implementation with a an new approach based on a stored procedure taking a table-valued parameter.

Entity Framework implementation – very slow

The original code, using Entity Framework 6 (altered to use a table / object type of “Employee” instead of the actual type I was working with):

DateTime now = DateTime.Now;
using (MyCustomContext context = new MyCustomContext())
{
    foreach (Employee employee in employeeData)
    {
        // Get the matching Employee record from the database, if there is one.
        Employee employeeRecord = context.Employees
            .Where(e => e.EmployeeID == employee.EmployeeID)
            .SingleOrDefault();

        bool isNewRecord = false;
        if (employeeRecord == null)
        {
            // We don't have a record in the database for this employee yet, 
            // so we'll add a new one.
            isNewRecord = true;
            employeeRecord = new Employee()
            {
                EmployeeID = employee.EmployeeID,
                CreationDate = now
            };
        }

        employeeRecord.ModificationDate = now;
        employeeRecord.FirstName = employee.FirstName;
        // (Set the remaining attributes...)

        if (isNewRecord)
        {
            context.Employees.Add(employeeRecord);
        }

        context.SaveChanges();
    }
}

That approach was taking around 300 seconds per 1000 records inserted.  It was bogging down my application in situations where I needed to insert/update tens of thousands of records at once.

Stored Procedure + Table-Valued Parameter implementation – fast!

In my testing, the revised approach below, replacing the Entity Framework implementation with a stored procedure taking a table-valued parameter, was able to upsert the same 1000 records in 0.5 second – a huge improvement!

I needed to add a custom table type with columns matching the Employees table:

CREATE TYPE EmployeesTableType AS TABLE
(
    [EmployeeID] [int] NOT NULL,
    [CreationDate] [datetime] NOT NULL,
    [FirstName] [nvarchar(100)] NOT NULL,
    /* More fields here... */
);

Next, the stored procedure to perform the upsert, taking input of an instance of the custom EmployeesTableType, and using the SQL Server MERGE command:

CREATE PROCEDURE dbo.UpsertEmployees
    @UpdateRecords dbo.EmployeesTableType READONLY
AS
BEGIN
    MERGE INTO Employees AS Target
    USING @UpdateRecords AS Source
    ON Target.EmployeeID = Source.EmployeeID
    WHEN MATCHED THEN
        UPDATE SET Target.EmployeeID = Source.EmployeeID,
            Target.FirstName = Source.FirstName,
            /* More fields here... */
    WHEN NOT MATCHED THEN           
        INSERT (EmployeeID,
            FirstName,
            /* More field names here... */
            )
        VALUES (Source.EmployeeID,
            Source.FirstName,
            /* More field values here... */
            );
END

Finally, here’s the C# code I used to execute the stored procedure:

public static void UpsertEmployeeData(List<Employee> employees)
{
    string connectionString = MyCustomMethodToGetConnectionString();
    using(SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        using (SqlCommand command = connection.CreateCommand())
        {
            command.CommandText = "dbo.UpsertEmployees";
            command.CommandType = CommandType.StoredProcedure;

            SqlParameter parameter = command.Parameters.AddWithValue("@UpdateRecords",
                CreateUpdateRecordsSqlParam(employees));  // See implementation below
            parameter.SqlDbType = SqlDbType.Structured;
            parameter.TypeName = "dbo.EmployeesTableType";

            command.ExecuteNonQuery();
        }
    }
}

private static DataTable CreateUpdateRecordsSqlParam(IEnumerable employees)
{
    DataTable table = new DataTable();
    table.Columns.Add("EmployeeID", typeof(Int32));
    table.Columns.Add("FirstName", typeof(string));
    // More fields here...

    foreach (Employee employee in employees)
    {
        table.Rows.Add(employee.EmployeeID,
            employee.FirstName,
            // More fields here...
    }

    return table;
}

Ideally, this post will serve as a useful reference the next time I, or you, need to code up a bulk upsert into SQL Server!

Credit to this StackOverflow answer by Ryan Prechel which was the primary inspiration for this approach.

Wednesday, July 13, 2016

C# Reflection: Setting a private enum-type member variable with a private inner enum type value

Today, while creating a C# unit test, I had a situation where I needed to set the value of a private variable on the class under test.  The variable was an enum-type variable, where the enum type itself was a private inner type defined in the class under test.

(I won’t in this post get into why I ended up landing on doing this, instead of some other solution such as refactoring the actual class under test in order to avoid the need to do so, as that would be a separate discussion.)

This post describes the technique using reflection that I ended up using to accomplish this.

For example, given a class defined like:

class Card
{
    private Suit _suit;

    private enum Suit
    {
        Hearts,
        Diamonds,
        Clubs,
        Spades
    }
}

Given an instance of that class named card, I was able to set the value of that object's private _suit variable by doing:

using System.Reflection;

...

// Get a reference to the _suit member variable.
FieldInfo suitField = card.GetType().GetField("_suit", BindingFlags.NonPublic | BindingFlags.Instance);

// Get a reference to the Spades member of the Suit enum.
object spades = card.GetType().GetNestedType("Suit", BindingFlags.NonPublic).GetField("Spades").GetValue(card);

// Set the value of _suit on our card object to Spades.
suitField (card, spades);

This kind of reflection hackery probably isn’t a best practice in most situations! Still, I thought it might be helpful to record here as an aid for those rare situations where it does make sense to manipulate this kind of enum-type private variable for unit testing purposes.

Wednesday, January 27, 2016

Entity Framework perf tip: Turn off AutoDetectChangesEnabled when doing bulk inserts

I was working on a situation this morning where, as part of a C# unit test method using Entity Framework 6 for database access, I was inserting about 1000 records into a SQL Server database.

This test was taking around 30-35 seconds to run, and I wanted to speed it up.  I tried re-coding the program to do the inserts using raw SQL, and that sped things up by about a factor of 3.

Thanks to a tip I found in a StackOverflow answer by “Steve”, I was able to get the same perf increase using Entity Framework by simply disabling AutoDetectChangesEnabled:

mycontext.Configuration.AutoDetectChangesEnabled = false;

Doing that before the loop with my calls to .Add() sped up the EF code to the point where it was performing just as well as the raw SQL. 

So, in situations where you’re using EF to do lots of inserts and you don’t need AutoDetectChangesEnabled (because you’re not also doing any updates to existing records), try turning it off for a possible nice performance improvement.

More info on this from Microsoft EF team member Arthur Vickers: Secrets of DetectChanges Part 3: Switching off automatic DetectChanges

Tuesday, January 05, 2016

Check the “Server” HTTP header for the source of an error returned from IIS

When an error response is returned from an HTTP request submitted to an IIS web server, the error response might actually be coming from http.sys (the “Hypertext Transfer Protocol Stack”), which processes incoming HTTP requests before they are passed along to IIS.

You can determine the source of the error by looking at the “Server” HTTP header in the returned HTTP response.  An error coming from http.sys will have the header:

Server:Microsoft-HTTPAPI/2.0

An error coming from IIS will instead have a header like:

Server:Microsoft-IIS/XX.X

Here’s some handy C# code to dump all headers from a given WebResponse to the console:

for (int i = 0; i < response.Headers.Count; i++) 
{ 
    string header = response.Headers.GetKey(i); 
    string[] values = response.Headers.GetValues(i); 
    Console.WriteLine(header + ": " + String.Join(", ", values)); 
}

Bonus tip: For a bit more information on errors generated by http.sys, check out the log files in this folder on the web server PC:

%windir%\System32\LogFiles\HTTPERR

References:

Monday, December 21, 2015

Fix: “The default DbConfiguration instance was used by the Entity Framework before the '...' type was discovered” in LINQPad

For a while now, I’ve been using the excellent LINQPad to quickly run .Net Entity Framework queries using the actual object model and database mappings from one of my projects, via a DbContext connection pointed to my project’s compiled .dll file and web.config file set up in LINQPad.

Recently, after this having been working fine for a while, I started getting an error when trying to execute any queries using this DbContext connection in LINQPad:

The default DbConfiguration instance was used by the Entity Framework before the '...' type was discovered.

The "..." in that error message was actually the name of a new class that had been added to my .Net project, which derived from the DbConfiguration class.

The fix was, in my project’s web.config file, to add to the entityFramework element a codeConfigurationType attribute pointing to the new class and its package.  So, whereas before my web.config file had:

<entityFramework>
    ...
</entityFramework>

I changed it to:

<entityFramework codeConfigurationType="MyProject.MyPackage.MyCustomDBConfiguration, MyProject.MyPackage">
    ...
</entityFramework>

(Where "MyProject", "MyPackage", and "MyCustomDBConfiguration" all obviously are replaced by the actual project, package, and class names from my actual project.)

With that change in place, I was able to successfully execute queries using my project’s EF model once again.

Update 2016-06-06: A second possible cause of this same issue is if the path to your application config file (or web.config file) in LinqPad's Connection Properties dialog is incorrect.

I had this issue occur just now after moving my project to a new location on disk. I'd corrected the "Path to Custom Assembly" value in the Connection Properties dialog, but I initially neglected to make the corresponding filesystem path change to the the "Path to application config" value.

Tuesday, June 09, 2015

System.Data.Entity.Core.EntityCommandExecutionException

Problem: A particular LINQ-to-SQL query selecting fields from a SQL Server view in a C# program, which ran fine in my local dev environment, produced an exception when run in the staging environment:

Exception Message: An error occurred while executing the command definition. See the inner exception for details. 

Exception Trace: System.Data.Entity.Core.EntityCommandExecutionException 
at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) 
at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues) 
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) 
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.b__5() 
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation) 
at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) 
at System.Data.Entity.Core.Objects.ObjectQuery`1..GetEnumerator>b__0() 
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext() 
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) 
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 
at [My code ...] 

Resolution: I had neglected to deploy to the staging environment (where the query was failing) a recently-created Entity Framework migration, which added a new output field to the SQL Server view being queried.  The query was failing because it was trying to select a field which didn’t actually exist on the target view.

Upon closer examination, when I reproduced the error and inspected the inner exception (which wasn’t being automatically written to the application’s error log), it was indeed of type SqlException and had the helpful message “Invalid column name ‘[my column name]’”.

So, things to try next time I see this exception:

  • Examine the inner exception (as suggested by the outer exception’s error message).
  • Make sure all Entity Framework migrations have been deployed to the target environment (if EF is in use).
  • Check and see whether the query is trying to select a field that doesn’t exist.

Monday, April 06, 2015

Getting the fractional portion of a number in C#

Quick technique for “truncating” the integer portion of a decimal value in C#, leaving only the fractional portion:

    static decimal GetFractionalPortion(decimal d)
    {
        return d % 1; 
    }

Calling that method with the value 12.34 will return 0.34.

This works because the modulo operator (%) returns the remainder after dividing the first operand by the second, and any value divided by 1.0 returns the fractional portion of the value.

Note that if a negative value is used, the return value (the fractional portion) will also be negative.

Thursday, March 19, 2015

C#: Default value for int? and other nullable types

If you’re a C# developer, you’re probably aware of the nullable versions of primitive types such as int. Just declare the variable with a question mark added to the type, like so:

int? i;

And presto, you have an int variable to which you can assign null!  Very handy for working with nullable number fields in databases, among other uses.

Before today, the above was pretty much the extent of my knowledge of C# nullable types.  As far as I was concerned, they were just “magic” versions of the corresponding primitives.

I ran into a situation today, though, that led me to investigate more deeply.  I had a class with a nullable type field for which no default value was explicitly assigned, as in this simplified example:

    Class MyClass
    {
         public int? I { get; set; }
    }

I needed to determine whether the field had been assigned a value other than the default value.  That led me to ask the question: What is the default value for an unassigned nullable int? instance variable in C#?  Is it null, like for reference types?  Or is it 0, like for int?

Surprisingly, searching Google didn’t immediately lead to a clear answer; nor did there seem to be a question on StackOverflow asking for this particular information.  The MSDN article Nullable Types (which was the first Google hit for terms C# nullable default value) didn’t have a clear answer.

It was the work of just a couple of minutes to write and run a bit of code to test the behavior using LINQPad.  The answer: The default value of a C# int? is null.

So int? defaults to null.  But why?

I was curious: Why is the default value null, not 0?  So I did some investigating, and ended up learning the following:

  • int? is syntactic sugar for the type Nullable<T> (where T is int), a struct.  (Per that Nullable Types MSDN article.)
  • The Nullable<T> type has a bool HasValue member, which when false, makes the Nullable<T> instance "act like" a null value.  In particular, the Nullable<T>.Equals method  is overridden to return true when a Nullable<T> with HasValue==false is compared with an actual null value.
  • From the C# Language Specification 11.3.4, a struct instance's initial default value is all of that struct's value type fields set to their default value, and all of that struct's reference type fields set to null. 
  • The default value of a bool variable in C# is false (reference). 

Therefore, the HasValue property of a default Nullable<T> instance is false; which in turn makes that Nullable<T> instance itself act like null.

Since there was no readily-available information on this topic in StackOverflow, I went ahead and posted it there as a new question and answer.

A null int? just simulates an actual null value

An interesting aspect of an int? merely “simulating” a null value, rather than actually being one, is that you can call methods on a null-value int? without a NullReferenceException occurring!  For example, this code using a null String throws a NullReferenceException:

    String s = null;
    s.GetHashCode(); // Throws NullReferenceException

The same code, though, used with a null Nullable<T>, does not throw an exception:

    int? n = null;
    n.GetHashCode(); // Returns 0

Wednesday, October 15, 2014

System.Uri (.NET Framework 4.5) – A Visual Guide

Since I’ve repeated enough times the somewhat cumbersome exercise of inferring what the various properties of the .NET Framework (as of version 4.5) System.Uri class return for a “typical” HTTP/HTTPS URL from the official documentation – and generally resorted to manual testing to be 100% certain of the behavior – here’s a visual guide.

Given a System.Uri instance constructed as follows (C#):

System.Uri uri = new System.Uri("https://www.example.com:8080/dir1/dir2/page.aspx?param1=val1&param2=val2#anchor");

Here’s what the various relevant properties of that Uri instance return:

Property String value
AbsoluteUri
https://www.example.com:8080/dir1/dir2/page.aspx?param1=val1&param2=val2#anchor
OriginalString
https://www.example.com:8080/dir1/dir2/page.aspx?param1=val1&param2=val2#anchor
Scheme
https
Host
        www.example.com
Authority
        www.example.com:8080
Port
                        8080
AbsolutePath
                            /dir1/dir2/page.aspx                            
PathAndQuery
                            /dir1/dir2/page.aspx?param1=val1&param2=val2
Query
                                                ?param1=val1&param2=val2
Fragment
                                                                        #anchor

The Segments property returns the following String array:

String[] {
    "/",
    "dir1/",
    "dir2/",
    "page.aspx"
}

Hopefully this will save a little time for all of you as well as for me!

Wednesday, September 10, 2014

C# – Shorten null check around foreach loops

This is another blog post filed under “So I can remember this for next time. If it helps you too, great!”

In C#, when looping over a collection where the collection object itself might be null, if the desired behavior is to just loop zero times if the collection object is null, typical code would be:

List<MyType> list = PopulateList(); // Some method that returns a List<MyType>, or null 
if (list != null) 
{ 
  foreach (MyType mt in list) 
  { 
    // Do stuff with mt... 
  }
}

Using the C# null-coalescing operator ??, the above code can be condensed to:

List<MyType> list = PopulateList(); // Some method that returns a List<MyType>, or null
foreach (MyType mt in list ?? Enumerable.Empty<MyType>) 
{ 
  // Do stuff with mt... 
}

In that second example, if list is non-null, then the foreach iterates over it as normal. If list is null, then the foreach iterates over an empty collection -- so zero iterations are performed.

Monday, December 24, 2007

C#/Java/C++: Combining a variable assignment and evaluation

Pop Quiz! C#/Java/C++/Javascript/(probably others, too!) programmers, off the top of your head, what's the result of evaluating a variable assignment? In other words, to take a specific example, what is the output of this Java code snippet:

int n;
System.out.println(n = 50);
(Feel free to substitute in Console.Out.WriteLine (C#) or good old printf (C++) for the System.out.println in that snippet, depending on your language of choice.)

The answer is: 50. In Java and the other languages mentioned, the result of the evaluation of a variable assignment is the value being assigned.

I just came across this construct myself for the first time while I recently was doing a code review of a colleague's Java code. Somehow, prior to that code review, I had managed to go for over a decade of developing in these various languages without running across this!

The reason I hasn't run across this before may have to do with code readability. Doing two different things at once (in this case, a combined variable assignment and evaluation) often isn't very good for code readability (and therefore for ease of maintainability); in the general case, then, it probably makes the most sense for the variable assignment and evaluation to just be separated into two separate lines of code.

However, as my colleague's code demonstrated, combining an assignment with an evaluation can be useful when setting up a loop where the same statement is executed to assign a value to the loop variable both before the loop starts, and on each subsequent iteration of the loop. For example, here's a Java example of reading data from an input file a line at a time, using a java.io.BufferedReader:

String inputLine;
while ((inputLine = bufferedReader.readLine()) != null)
{
    // Do something with inputLine...
}

The while statement in this case combines the assignment of the variable inputLine to the line of text read from the BufferedReader, with the check to stop looping when inputLine is null.

In the past, I've written the same logic in this manner:

String inputLine = bufferedReader.readLine();
while (inputLine != null)
{
    // Do something with inputLine...

    inputLine = bufferedReader.readLine();
}

I had always been kind of annoyed over the need to repeat the assignment (inputLine = bufferedReader.readLine()) in two different places.

For writing loops like this in the future, I'll have to think more about whether the gain in code brevity (and debatably, in elegance) from using the former approach (the combined assignment/evaluation in the while statement) is worth the potential cost for future maintainers in the readability of the code.

Friday, December 08, 2006

Returning values from C# event handlers

C# events are typically used when a class instance that needs to notify other class instances that reference it that something has taken place.

In some cases, it is useful for an event handler to respond to the event by sending data back to the instance that fired the event. For example, in response to an event fired to give notification that a particular operation is starting, an event handler for the event could respond by returning a boolean value to indicate that the operation should either proceed normally or be aborted.

There are a couple of ways in which returning data in response to handling an event in this manner can be set up.

One is for the event handler method to set a parameter on one of the event method arguments. The System.ComponentModel.CancelEventArgs class is a good example of this. The CancelEventArgs class has a public Boolean property, Cancel, that the event handler method can set to True to indicate that the operation associated with the fired event should be aborted.

A second way for an event handler method to return a value back to the sender is for the delegate that the event is based on to include just that -- a return value. Instead of being declared to return void, the delegate on which the event is based can be defined to return a type such as bool or int.

What happens, though, if there is more than one handler for the event, both of which set the return value (either in a property of one of the event method arguments, or in the return value itself)?

The answer (at least in a single-threaded scenario) is “last-one-in-wins” -- that is, the last event handler method to run is the one whose return value will be received by the code that fired the event. (Event handlers run in the order in which they were registered. A good example of this which uses just plain delegates (not events) can be found in section 15.3 of the C# Language Specification.)

For example, consider this code, which wires up 3 separate event handlers to the event fired by the EventSource class, each of which set the value of the Data parameter of the event’s argument:

class Program
{
  public static void Main(string[] args)
  {
    EventSource eventSource = new EventSource(); 
    Handler handler1 = new Handler(1, eventSource);
    Handler handler2 = new Handler(2, eventSource);
    Handler handler3 = new Handler(3, eventSource);

    eventSource.FireEvent();
  }
}

/// 
/// The IntEventArgs class extends the basic EventArgs class 
/// to add a public parameter of type int named Data.
/// 
class IntEventArgs : EventArgs
{
  public int Data = -1;
}

/// 
/// The EventSource class fires an event that passes an 
/// IntEventArgs as a parameter.
/// 
class EventSource
{
  public delegate void ReturnIntHandler
    (object sender, IntEventArgs eventArgs);
  public event ReturnIntHandler ReturnIntEvent;

  public void FireEvent()
  {
    Console.Out.WriteLine("[EventSource] Firing event...");

    IntEventArgs eventArgs = new IntEventArgs();
    ReturnIntHandler e = this.ReturnIntEvent;
    if (e != null)
    {
      e(this, eventArgs);
    }

    Console.Out.WriteLine("[EventSource] Finished firing event. "
      + "eventArgs.Data: " + eventArgs.Data);
  }
}

/// 
/// The Handler class gets assigned an ID value when it is created 
/// (to distinguish it from other instances of the Handler class), 
/// and handles events of type ReturnIntEvent.
/// 
class Handler
{
  private int _id;

  public Handler(int id, EventSource eventSource)
  {
    this._id = id;
    eventSource.ReturnIntEvent +=
      new EventSource.ReturnIntHandler(eventSource_ReturnIntEvent);
  }

  private void eventSource_ReturnIntEvent
    (object sender, IntEventArgs eventArgs)
  {
    Console.Out.WriteLine("[Handler (" + this._id + ")] "
      + "Handling event, setting Data to " + this._id + ".");
    eventArgs.Data = this._id; 
  }
}

This code produces the following output. Note that the final value of the eventArgs.Data parameter (3) matches the value set by the last event handler method to handle the event.

[EventSource] Firing event...
[Handler (1)] Handling event, setting data to 1.
[Handler (2)] Handling event, setting data to 2.
[Handler (3)] Handling event, setting data to 3.
[EventSource] Finished firing event. eventArgs.Data: 3

Monday, October 23, 2006

DragDropEffects.Link bit not included in DragDropEffects.All value (.Net 2.0)

I just spent a frustrating few minutes trying to figure out what looked to me like some unexpected behavior in the code (C# 2.0) for a drag/drop operation in a Windows Forms component. In the handler for a DragOver event, I was setting the Effect property of the DragEventArgs argument to DragDropEffects.Link, but then subsequently in my GiveFeedback event handler, the Effect property of the GiveFeedbackEventArgs was coming back as None.

In other words, I was essentially doing this in my DragOver event handler:

private void HandleDragOver(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Link;
}

And then seeing this result in my GiveFeedback event handler:

private void HandleGiveFeedback(object sender,
  GiveFeedbackEventArgs e)
{
    if (e.Effect == DragDropEffects.Link)
    {
        // (Execution not making it here -- value of 
        // e.Effect is DragDropEffects.None!)
    }
}

I figured out that the problem was that I was using this line of code to start the drag operation:

DoDragDrop(dragData, DragDropEffects.All);

See the problem? I didn't, at first.

The DragDropEffects enumeration is a FlagsAttribute enum with the following members: All, Copy, Link, Move, Scroll, and None. At the time that I coded the DoDragDrop line of code above, I had made the assumption that the All value of the enumeration was defined as:

Copy | Link | Move | Scroll

That is, a bitwise OR combination of all of the members of the enum aside from the None member.

However, looking that the value of System.Windows.Forms.DragDropEffects.All in the Visual Studio debugger, the value is actually defined as:

Copy | Move | Scroll

The Link member is not present! This is why my GiveFeeback event handler was failing to recognize DragDropEffects values of Link -- Link was not actually being specified in the allowedEffects parameter (argument 2) of my DoDragDrop call.

Since what I really wanted to accomplish was to support Move and Link operations, I changed my DoDragDrop call to:

DoDragDrop(dragData, DragDropEffects.Move | DragDropEffects.Link);

This did have the desired effect of getting my GiveFeedback event handler method to support DragDropEffects values of Link.

The fact that DragDropEffects.All does not include the value for Link isn't clearly spelled out on the MSDN help page for DragDropEffects. The description for the All member does say "The data is copied, removed from the drag source, and scrolled in the drop target," but you need to be paying pretty close attention to notice that "Link" isn't mentioned, even assuming that you check the help before using the member in the first place! Similarly, the example code given on the help page for DoDragDrop does use DragDropEffects.All | DragDropEffects.Link in its call to DoDragDrop, but the use of the Link member there isn't called out or noted with a comment.

Due to its counter-intuitive nature, I would go so far as to call the omission of the DragDropEffects.Link bit from the DragDropEffects.All value non-standard... if the DragDropEffects enum wasn't a part of the standard .Net Framework library! :-) Perhaps there is a good historical (legacy support) reason for the exclusion, but if so, it isn't at all clear from just looking at the documentation.

Thursday, August 17, 2006

IE doesn't respect set-only properties in hosted Windows Forms controls

While working on a simple Windows Forms control to determine how Windows XP styles are supported in Windows Forms 2.0 controls hosted in Internet Explorer -- more on that later -- I found that Internet Explorer 6 doesn't respect public properties of hosted/embedded controls that define a "set" but not a "get".

I had a property like this in my test control:

public bool UseRedBackgroundColor
{
  set
  {
    if (value == true)
    {
      this.BackColor = Color.Red;
    }
  }
}

I had a param set in the object tag in my test HTML page to set the property to true, but the control didn't render with the red background:

<object id="XPTest" name="XPTest"
classid="http:/webtest/XPStylesTest.dll
#XPStylesTest.XPStylesTest"
    width="158" 
    height="250">
  <param name="UseRedBackgroundColor" value="True" />
</object>

I changed my public property to have a "get" section, and after a rebuild of the project and a reopen of IE, the control rendered with a red background as expected:

public bool UseRedBackgroundColor
{
  get
  {
    return (this.BackColor == Color.Red);
  }
  set
  {
    if (value == true)
    {
      this.BackColor = Color.Red;
    }
  }
}

So if a public property of a Windows Forms control hosted in IE isn't being activated as expected, check to make sure that a "get" section has been defined for the property.

Monday, June 05, 2006

C# String Literals and the '@' Character

Specifying Windows file paths in C# code can result in some messy-looking string literals, due to the need to specify "\\" as each backslash character to avoid having a single backslash character be interpreted as the beginning of an escape sequence. For example:

string myAppPath = "C:\\Program Files\\MyApp";

(For the purposes of this post, I'm ignoring the fact that assuming that "myApp" will always be located at "C:\Program Files\" may not be a good idea.)

A way to make this look cleaner (and possibly be less confusing) is to use a '@' character prior to the string literal. The '@' character makes C# skip looking for any escape characters in the string (with the exception of the \" escape sequence). This use of the '@' character before a string literal is called a verbatim string literal. The file path declaration above, revised to use a verbatim string literal, would be:

string myAppPath = @"C:\Program Files\MyApp";

For more details on verbatim string literals, see the string literals page in the C# Language Specification.

Also, the Visual Studio IDE supports displaying verbatim string literals in a different color than standard string literals, for further clarity. I have my Visual Studio installations configured to display standard string literals in off-white and verbatim string literals in red.

Saturday, February 11, 2006

Fix: COMException accessing DirectoryEntry.Properties["path"]

Earlier tonight, I was testing some C# 1.1 code that gets the physical path to an IIS virtual directory. I ran into a problem where for certain virtual directories on my test machine, a System.Runtime.InteropServices.COMException was thrown when trying to access the System.DirectoryServices.DirectoryEntry.Properties["path"] property for the directory's DirectoryEntry, whereas for other virtual directories, the code worked as expected.

After searching around using Google Groups briefly, I came across a microsoft.public.adsi.general post that ended up leading me to the answer. The post mentioned a property called "KeyType" of which I had been previously unaware.

Apparently, there are (at least) two types of IIS 5.1 virtual directories. The standard type has a DirectoryEntry.Properties["KeyType"] value of "IIsWebVirtualDir".

There is also a second type, which has a KeyType value of "IIsWebDirectory". Such virtual directories show up in inetmgr with the usual "virtual directory" icon (not the yellow "plain folder" icon) in the folder list in the right pane, but in the Properties dialog on the Directory tab, the Local Path field is disabled for such directories.

For "IIsWebDirectory" type directories, an attempt to access the DirectoryEntry.Properties["path"] property for the directory (to get the physical path to the directory) results in the System.Runtime.InteropServices.COMException ("Exception from HRESULT: 0x80005006") being thrown.

I ended up working around this issue by assuming any directories of type IIsWebDirectory are located under the root IIS virtual directory (for which DirectoryEntry.Properties["path"] does return a valid result). Unfortunately, I wasn't able to turn up any documentation on IIsWebDirectory-type directories to verify this assumption, but it seems reasonable given that the Local Path field in inetmgr for such directories is disabled.