InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Exchange Managed API autodiscover with Powershell

Powershell is a great tool to automate all sorts of things – including fiddling around with your Exchange mailbox. And the Autodiscover makes it really easy to connect to it – especially if you’re on Office 365 and don’t even know your CAS server.

So first, we need to load the EWS Managed API dll into the current runspace:

[Reflection.Assembly]::LoadFrom("C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll")

Then, create an ExchangeService instance and set its credentials:

$service =  New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$service.Credentials = New-Object System.Net.NetworkCredential("someone@infinitec.de", "password", "domain");

Now we are ready to use AutoDiscover. But depending on your infrastructure, AutoDiscover might need to follow some redirections before it has discovered your CAS Server. Like in this case:

$service.AutodiscoverUrl("someone@infinitec.de");

Exception calling "AutodiscoverUrl" with "1" argument(s): "Autodiscover blocked a potentially insecure redirection to https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml. To allow Autodiscover to follow the redirection, use the AutodiscoverUrl(string, AutodiscoverRedirectionUrlValidationCallback) overload."
At line:1 char:25
+ $service.AutodiscoverUrl <<<< ("hkrause@infinitec.de");
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

This happens because the AutoDiscover process looks at autodiscover.infinitec.de and instead of an A record pointing to the AutoDiscover service, it finds a CNAME redirecting it to autodiscover.outlook.com. Because this might pose a security risk, the AutoDiscoverUrl method aborts  the discovery process and throws the Exception displayed above. The solution is also outlined: Instead of calling the method AutoDiscoverUrl(mailAddress) call the overload which expects a delegate as a second paramter. This delegate has a string as input and returns the $true if the discovery process should follow the redirection; false otherwise.

How can this overload be used with PowerShell? The answer is a ScriptBlock. If you simply want to allow the discovery process to follow all redirects, simply call it this way:

$service.AutodiscoverUrl("someone@infinitec.de", {$true})

But if you want to verify the discovery process is redirected to the correct url, use this version:

$TestUrlCallback = {
 param ([string] $url)
 if ($url -eq "https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml") {$true} else {$false}
}

$service.AutodiscoverUrl("someone@infinitec.de", $TestUrlCallback)

You can embed whatever checks you need to verify the given url in the third line of the $TestUrlCallback method.


Posted by Henning Krause on Friday, July 22, 2011 5:30 PM, last modified on Sunday, July 24, 2011 1:22 AM
Permalink | Post RSSRSS comment feed

Replying with attachments to an email message with EWS

The EWS Managed API makes some tasks really easy – like replying to an existing email. Given the unique id of an item, this can be done this way:

var message = (EmailMessage) Item.Bind(service, new ItemId(uniqueId), PropertySet.FirstClassProperties);
var reply = message.CreateReply(false);
reply.BodyPrefix = "Response text goes here";
reply.SendAndSaveCopy();

But what if you want to send an attachment along with the reply? This is tricky, because the the instance created by the EmailMessage.CreateReply() method is of type ResponseMessage. Since its not an EmailMessage instance, it does not have an Attachment property. To add an attachment to this reply, it needs to be saved first. The Save method returns an EmailMessage instance. Attachments can be added to this message. Finally, the message can be sent to its destination.

var message = (EmailMessage) Item.Bind(service, new ItemId(uniqueId), PropertySet.FirstClassProperties);
var reply = message.CreateReply(false);
reply.BodyPrefix = "Response text goes here";
var replyMessage = reply.Save(WellKnownFolderName.Drafts);
replyMessage.Attachments.AddFileAttachment("d:\\inbox\\test.pdf");
replyMessage.Update(ConflictResolutionMode.AlwaysOverwrite);
replyMessage.SendAndSaveCopy();

Posted by Henning Krause on Monday, July 18, 2011 8:04 PM, last modified on Monday, July 18, 2011 8:04 PM
Permalink | Post RSSRSS comment feed

Using Streaming Notifications with Exchange 2010

That is the title of an article I wrote for Microsoft. It has been published here a few days ago:

Summary: Streaming notifications, which combine the functionalities of push and pull notifications, are new in Microsoft Exchange Server 2010 Service Pack 1 (SP1). This article explains how streaming notifications work and when to use them.

The code sample is missing, but that will be fixed in a few days.


Posted by Henning Krause on Friday, July 15, 2011 7:50 PM, last modified on Saturday, July 30, 2011 10:38 PM
Permalink | Post RSSRSS comment feed

Enumerating Sharepoint Connections in a mailbox with EWS

An interesting question on StackOverflow came up recently: Is it possible to get the SharePoint lists which are connected to an Exchange Mailbox? The data which is synchronized with Outlook is stored in a PST file on the local disk – so no interaction with Exchange on this end. But if a user logs on from another computer, the SharePoint list the user has subscribed to are synchronized there as well. So the configuration seems to be stored in the mailbox somewhere. And indeed, they are. Outlook creates a message item in the associated folder table in the users inbox. Associated items are not visible from Outlook, but they can be accessed using MAPI or EWS. It turns out that Outlook saves the SharePoint connections similar to the RSS feeds. So a good starting point is to have a look at the Sharing Message Object Protocol Specification which lists the properties used for these items.

The SharePoint configuration items have a MessageClass of IPM.Sharing.Index.In, and the property PidLidSharingProviderGuidProperty is set to {0006F0AD-0000-0000-C000-000000000046}.

The configuration data is stored on a few properties. The following method lists all SharePoint connections connected to a mailbox:

   1:  using System;
   2:  using System.Net;
   3:  using Microsoft.Exchange.WebServices.Data;
   4:   
   5:  namespace ExchangeTest
   6:  {
   7:      internal class Program
   8:      {
   9:          private static readonly Guid PropertySetSharing = new Guid("{00062040-0000-0000-C000-000000000046}");
  10:   
  11:          private static readonly ExtendedPropertyDefinition PidLidSharingProviderGuidProperty =
  12:              new ExtendedPropertyDefinition(PropertySetSharing, 0x8A01, MapiPropertyType.CLSID);
  13:   
  14:          private static readonly ExtendedPropertyDefinition SharingRemotePathProperty =
  15:              new ExtendedPropertyDefinition(PropertySetSharing, 0x8A04, MapiPropertyType.String);
  16:   
  17:          private static readonly ExtendedPropertyDefinition SharingLocalNameProperty =
  18:              new ExtendedPropertyDefinition(PropertySetSharing, 0x8A0F, MapiPropertyType.String);
  19:   
  20:          private static readonly ExtendedPropertyDefinition SharingRemoteNameProperty =
  21:              new ExtendedPropertyDefinition(PropertySetSharing, 0x8A05, MapiPropertyType.String);
  22:   
  23:          private static readonly ExtendedPropertyDefinition SharingBrowseUrlProperty =
  24:              new ExtendedPropertyDefinition(PropertySetSharing, 0x8A51, MapiPropertyType.String);
  25:   
  26:          private static readonly ExtendedPropertyDefinition SharingRemoteTypeProperty =
  27:              new ExtendedPropertyDefinition(PropertySetSharing, 0x8A1D, MapiPropertyType.String);
  28:   
  29:          private static readonly Guid SharePointProviderId = new Guid("{0006F0AD-0000-0000-C000-000000000046}");
  30:   
  31:          public static void Main(string[] args)
  32:          {
  33:              var service = new ExchangeService(ExchangeVersion.Exchange2010)
  34:                            {Credentials = new NetworkCredential(test@contoso.com, "Password!")};
  35:              
  36:              service.AutodiscoverUrl(test@contoso.com, url => true);
  37:   
  38:              var folder = Folder.Bind(service, WellKnownFolderName.Inbox);
  39:              var filter = new SearchFilter.SearchFilterCollection(LogicalOperator.And,
  40:                                                                   new SearchFilter.IsEqualTo(ItemSchema.ItemClass,
  41:                                                                                              "IPM.Sharing.Index.In"),
  42:                                                                   new SearchFilter.IsEqualTo(PidLidSharingProviderGuidProperty,
  43:                                                                                              SharePointProviderId.ToString()));
  44:              var view = new ItemView(512)
  45:                         {
  46:                             Traversal = ItemTraversal.Associated,
  47:                             PropertySet = new PropertySet(BasePropertySet.IdOnly,
  48:                                                           SharingRemotePathProperty, SharingBrowseUrlProperty,
  49:                                                           SharingLocalNameProperty, SharingRemoteNameProperty,
  50:                                                           SharingRemoteTypeProperty)
  51:                         };
  52:   
  53:              var items = folder.FindItems(filter, view);
  54:              foreach (var item in items)
  55:              {
  56:                  Console.Out.WriteLine("RemotePath = {0}", item.GetValueOrDefault<string>(SharingRemotePathProperty));
  57:                  Console.Out.WriteLine("BrowseUrl = {0}", item.GetValueOrDefault<string>(SharingBrowseUrlProperty));
  58:                  Console.Out.WriteLine("LocalName = {0}", item.GetValueOrDefault<string>(SharingLocalNameProperty));
  59:                  Console.Out.WriteLine("Remotename = {0}", item.GetValueOrDefault<string>(SharingLocalNameProperty));
  60:                  Console.Out.WriteLine("Type = {0}", item.GetValueOrDefault<string>(SharingRemoteTypeProperty));
  61:                  Console.Out.WriteLine(new string('=', 80));
  62:              }
  63:          }
  64:      }
  65:   
  66:      public static class ItemExtension
  67:      {
  68:          public static T GetValueOrDefault<T>(this Item item, PropertyDefinitionBase property, T defaultValue = default(T))
  69:          {
  70:              T result;
  71:              return item.TryGetProperty(property, out result) ? result : defaultValue;
  72:          }
  73:      }
  74: }

This method dumps the configuration of all SharePoint connections to the console.

To use this method, you’ll need .NET 4. If you are running .NET 2.0, you’ll have to adapt it.

Additionally, this won't work with Exchange 2007, because EWS in that version does not allow a FindItems call on the associated items table. WebDAV is the API of choice in this case.


Posted by Henning Krause on Wednesday, July 13, 2011 9:05 PM, last modified on Wednesday, July 13, 2011 9:05 PM
Permalink | Post RSSRSS comment feed

Correlating a Non-Delivery-Notification to its original message with the Exchange Managed API

If you are automatically process emails in an Exchange Mailbox, you might also need to process non delivery reports (NDRs) and correlate these NDRs to their original values. Luckily, Exchange does most of the heavy lifting, as long as the NDR conforms to the RFC 3461, which defines the proper structure for an NDR that can be automatically parsed. Not all MTAs (Mail transfer agents) do generate these types of NDRs.

First of all, you need to check whether the mail item in question is actually a non delivery report. This is done by examining the Item Class of the mail. An NDR has an item class of REPORT.IPM.Note.NDR. Next, you need to retrieve the property PidTagParentKey from the item. This property contains the PidTagSearchKey of the original mail.

Unfortunately, the PidTagSearchKey cannot be used to bind to the item directly. Instead, you have to issue a FindItem operation to get it. Normally, sent items are all stored in the SentItems folder, so this narrows the search down.

Here is a sample method which describes the process:

 

   1:  class Program
   2:  {
   3:      private static readonly ExtendedPropertyDefinition PidTagParentKeyProperty = new ExtendedPropertyDefinition(0x25, MapiPropertyType.Binary);
   4:      private static readonly ExtendedPropertyDefinition PidTagSeachKeyProperty = new ExtendedPropertyDefinition(0x300B, MapiPropertyType.Binary);
   5:   
   6:   
   7:      private static bool TryGetOriginalMail(string ndrId, ExchangeService service, out Item originalItem)
   8:      {
   9:          byte[] value;
  10:   
  11:          var item = service.BindToItems(new[] {new ItemId(ndrId)},
  12:                                          new PropertySet(BasePropertySet.IdOnly,
  13:                                                          PidTagParentKeyProperty, ItemSchema.Subject)).First().Item;
  14:   
  15:          if (!item.TryGetProperty(PidTagParentKeyProperty, out value))
  16:          {
  17:              Console.Out.WriteLine("Correlationtoken not found.");
  18:              originalItem = null;
  19:              return false;
  20:          }
  21:   
  22:          originalItem = service
  23:              .FindItems(WellKnownFolderName.SentItems,
  24:                          new SearchFilter.IsEqualTo(PidTagSeachKeyProperty, Convert.ToBase64String(value)),
  25:                          new ItemView(1) {PropertySet = PropertySet.FirstClassProperties})
  26:              .FirstOrDefault();
  27:   
  28:          return true;
  29:      }
  30:  }

Posted by Henning Krause on Monday, June 27, 2011 8:12 PM, last modified on Monday, June 27, 2011 8:12 PM
Permalink | Post RSSRSS comment feed

From ArgumentException to CodeContracts using Resharper

Resharper (awesome tool btw) makes it really easy to add sanity checks to your code. Just hit Alt+Enter on a method parameter and select “Check parameter for null”:

image

 

This inserts this code:

public static void Test(Frob frob)
{
    if (frob == null) throw new ArgumentNullException("frob");
}

This is great, but once you have started working with Code Contracts (see here for a small tutorial on how to setup Code Contracts) you might want to migrate all those null checks to preconditions. Resharper offers a very powerful feature to to just that: Structural search and replace. It even goes so far that it will highlight parts of code and offers a quick-fix to change conventional argument checking into preconditions. All we need to do is to create a pattern which recognizes an old argument-null check and a replacement pattern:

  1. From the main menu, select ReSharper –> Tools–> Pattern catalog
  2. Click Add pattern
  3. In the search pattern edit box, add this line:
    if ($parameter$ == null) throw new ArgumentNullException($expression$);
  4. In the Replace pattern edit box, add this line:
    Contract.Requires($parameter$ != null);
  5. Click Add Placeholder and select Identifier. Name the placeholder parameter.
  6. Click Add Placeholder again and select Expression. Name the placeholder expression and select System.String as the expression type.
  7. Ensure that the Format after replace and Shorten references options are both checked.
  8. Click Save to persist the new pattern.

Resharper will immediately recognize traditional argument checking code and offer a replacement:

image

After the quickfix has been applied, the method looks like this:

public static void Test(Frob frob)
{
    Contract.Requires(frob != null);
}

If you have enabled runtime checking (as per my last post about this topic), a ContractException will be thrown then the precondition is not met. Obviously, this differs from the previous behavior, which caused this method to throw an ArgumentNullException. But as Eric Lippert states, ArgumentNullExceptions are boneheaded exceptions, and as such should never be cought – they simply shouldn’t happen in production code:

Boneheaded exceptions are your own darn fault, you could have prevented them and therefore they are bugs in your code. You should not catch them; doing so is hiding a bug in your code. Rather, you should write your code so that the exception cannot possibly happen in the first place, and therefore does not need to be caught. That argument is null, that typecast is bad, that index is out of range, you're trying to divide by zero – these are all problems that you could have prevented very easily in the first place, so prevent the mess in the first place rather than trying to clean it up.

(quoted from http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx)


Posted by Henning Krause on Monday, December 13, 2010 11:04 PM, last modified on Monday, December 13, 2010 11:04 PM
Permalink | Post RSSRSS comment feed

fun with .NET 4 expressions – Light speed edition

A few days ago I posted an article about the new .NET Expression features in .NET 4.0 (Fun with .NET 4 expressions). A few people commented and wrote the this was a pretty expensive way to synchronize data. Of course it was – performance wasn’t a design consideration. I merely followed the two rules of optimization:

  1. Don’t do it.
  2. (For experts only!) Don’t do it now.

And since the synchronization process was fast enough, I didn’t care.

However, just for the fun of it, I did some performance optimization and it is pretty amazing. The thing which made the original code rather slow was the fact that the same expressions were compiled over and over again. So an obvious improvement was to cache the compiled expressions and reuse them. So I introduced two dictionaries to hold the compiled expressions:

private static readonly Dictionary<Type, object> _SetterCache = new Dictionary<Type, object>();
private static readonly Dictionary<Type, object> _GetterCache = new Dictionary<Type, object>();

You may wonder why the type of the dictionary is Dictionary<Type, object>. The reason for this is that there is no other common base class for the type Func<TSource, TProperty>. The following this method checks the cache and compiles the expression if required:

private static Func<TTarget, TProperty> GetGetterMethod<TTarget, TProperty>(Expression<Func<TTarget, TProperty>> targetSelector)
{
    object getterObject;
    Func<TTarget, TProperty> getterMethod;
    var selectorType = targetSelector.Type;

    if (!_GetterCache.TryGetValue(selectorType, out getterObject))
    {
        getterMethod = targetSelector.Compile();
        _GetterCache[selectorType] = getterMethod;
    }
    else
    {
        getterMethod = (Func<TTarget, TProperty>) getterObject;
    }
    return getterMethod;
}

I added a similar method to handle the update expression accordingly.

Finally, I hacked together a small test program which used the Stopwatch class to measure the synchronization speed. The result is quite impressing. Synchronizing an object with two properties 10,000 times yielded these results:

Elapsed for 10000 rounds (Slow): 00:00:08.0471936
Elapsed for 10000 rounds (Fast): 00:00:00.2009293

That is quite an improvement.

I’ve attached the source code to this post, so you can measure yourself.

Downloads


Posted by Henning Krause on Sunday, December 5, 2010 9:00 PM, last modified on Sunday, December 5, 2010 8:38 PM
Permalink | Post RSSRSS comment feed

The case of the hanging WCF service [Updated]

Recently a co-worker was complaining about a windows service which took ages to start. Because this exact code runs on a large number of servers I suspected the the fault to be on the machine rather than the code. The task manager yielded no interesting information (memory consumption was ok and so was the CPU usage). So I downloaded and installed the Windows Debugging tools, configured the symbol server and attached the debugger to the process in question. To enable debugging of managed applications, the SOS extension has to be loaded:

.loadby sos mscorwks

The next step was to look what all the threads are doing:

!eestack –ee

The !eestack command lists the stacktraces of all running threads and the –ee option restricts the output to managed methods. This makes the trace much more readable. Anyway, most threads where just sitting around doing nothing, but one got my attention:

   1:  Thread   6 
   2:  *** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v2.0.50727_64\System\65f46521e7fca2cd2d216162175f2fd6\System.ni.dll 
   3:  *** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v2.0.50727_64\System.ServiceModel\e000a1cd822ffb6f6483426a67622d75\System.ServiceModel.ni.dll 
   4:  *** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v2.0.50727_64\Netatwork.Common\73da8de102292417562adaf43872eec6\Netatwork.Common.ni.dll 
   5:  *** ERROR: Module load completed but symbols could not be loaded for C:\Windows\assembly\NativeImages_v2.0.50727_64\Netatwork.Common\73da8de102292417562adaf43872eec6\Netatwork.Common.ni.dll 
   6:  Child-SP         RetAddr          Call Site 
   7:  0000000001f9e900 000007fef1b64304 System_ni!DomainBoundILStubClass.IL_STUB(UInt32, System.Security.Cryptography.SafeLocalAllocHandle, System.Security.Cryptography.OidGroup)+0x77 
   8:  0000000001f9ea00 000007fef1b2b402 System_ni!System.Security.Cryptography.CAPI.c(UInt32, System.Security.Cryptography.SafeLocalAllocHandle, System.Security.Cryptography.OidGroup)+0x94 
   9:  0000000001f9eac0 000007fef1b2b28c System_ni!System.Security.Cryptography.X509Certificates.X509Utils.FindOidInfo(UInt32, System.String, System.Security.Cryptography.OidGroup)+0x152 
  10:  0000000001f9eba0 000007fef1b282ec System_ni!System.Security.Cryptography.Oid..ctor(System.String, System.Security.Cryptography.OidGroup, Boolean)+0x2c 
  11:  0000000001f9ebe0 000007fef1b27f03 System_ni!System.Security.Cryptography.X509Certificates.X509Certificate2.get_PublicKey()+0x8c 
  12:  0000000001f9ec40 000007feee6c5425 System_ni!System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()+0xb3 
  13:  0000000001f9eca0 000007feee6c538d System_ServiceModel_ni!System.ServiceModel.Security.SecurityUtils.EnsureCertificateCanDoKeyExchange(System.Security.Cryptography.X509Certificates.X509Certificate2)+0x55 
  14:  0000000001f9ed20 000007feee6c5349 System_ServiceModel_ni!System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateServerX509TokenProvider()+0x2d 
  15:  0000000001f9ed60 000007feee6c52e1 System_ServiceModel_ni!System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateLocalSecurityTokenProvider(System.ServiceModel.Security.Tokens.RecipientServiceModelSecurityTokenRequirement)+0x49 
  16:  0000000001f9edc0 000007feef00fcd9 System_ServiceModel_ni!System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateSecurityTokenProvider(System.IdentityModel.Selectors.SecurityTokenRequirement)+0x41 
  17:  0000000001f9ee10 000007feef010a0f System_ServiceModel_ni!(System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateTlsnegoServerX509TokenProvider(System.ServiceModel.Security.Tokens.RecipientServiceModelSecurityTokenRequirement)+0xd9 
  18:  0000000001f9ee60 000007feee6c5811 System_ServiceModel_ni!System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateTlsnegoSecurityTokenAuthenticator(System.ServiceModel.Security.Tokens.RecipientServiceModelSecurityTokenRequirement, Boolean, System.IdentityModel.Selectors.SecurityTokenResolver ByRef)+0x23f 
  19:  0000000001f9eee0 000007feef624a7a System_ServiceModel_ni!System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateSecurityTokenAuthenticator(System.IdentityModel.Selectors.SecurityTokenRequirement, System.IdentityModel.Selectors.SecurityTokenResolver ByRef)+0x2a1 
  20:  0000000001f9ef40 000007feee77dc27 System_ServiceModel_ni!System.ServiceModel.Security.SymmetricSecurityProtocolFactory.OnOpen(System.TimeSpan)+0xe9fc7a 
  21:  0000000001f9efb0 000007feee6ebe43 System_ServiceModel_ni!System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(System.TimeSpan)+0x17 
  22:  0000000001f9efe0 000007feef18bf45 System_ServiceModel_ni!System.ServiceModel.Channels.CommunicationObject.Open(System.TimeSpan)+0x233 
  23:  0000000001f9f0d0 000007feef1881cb System_ServiceModel_ni!System.ServiceModel.Security.SecurityListenerSettingsLifetimeManager.Open(System.TimeSpan)+0x65 
  24:  0000000001f9f140 000007feee6ebe43 System_ServiceModel_ni!System.ServiceModel.Channels.SecurityChannelListener`1[[System.__Canon, mscorlib]].OnOpen(System.TimeSpan)+0xcb 
  25:  0000000001f9f1b0 000007feee727aa7 System_ServiceModel_ni!System.ServiceModel.Channels.CommunicationObject.Open(System.TimeSpan)+0x233 
  26:  0000000001f9f2a0 000007feee6ebe43 System_ServiceModel_ni!System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpen(System.TimeSpan)+0x57 
  27:  0000000001f9f2f0 000007feee6b936e System_ServiceModel_ni!System.ServiceModel.Channels.CommunicationObject.Open(System.TimeSpan)+0x233 
  28:  0000000001f9f3e0 000007feee6ebe43 System_ServiceModel_ni!System.ServiceModel.ServiceHostBase.OnOpen(System.TimeSpan)+0x6e 
  29:  0000000001f9f450 000007fef09bec81 System_ServiceModel_ni!System.ServiceModel.Channels.CommunicationObject.Open(System.TimeSpan)+0x233 
  30:  

For administrative reasons, this server exposes a number of encrypted WCF endpoints. During startup the WCF runtime examines the certificate and checks whether it is valid. During this operation, it tries to access the private key and calls the Win32 native function CryptFindOidInfo. As it turns out, this function may contact a domain controller to fetch certain information. This “feature” can be disabled by passing the CRYPT_OID_DISABLE_SEARCH_DS_FLAG to the function, but the .NET framework doesn’t do this. Apparently, the function had difficulties contacting its domain controller. A common cause for this is an incorrect DNS configuration, so I checked this first. As it turned out, the DNS configuration was quite complicated and a conditional forwarder for the domain the machine was on was missing. Once this was fixed, the startup speed of the service was back to normal.

Update

Alex from Decrypt my World has an article related to this problem and offers a different solution: http://blogs.msdn.com/b/alejacma/archive/2010/12/20/big-delay-while-calling-envelopedcms-constructor.aspx


Posted by Henning Krause on Tuesday, November 30, 2010 7:33 PM, last modified on Monday, December 20, 2010 2:33 PM
Permalink | Post RSSRSS comment feed

Enabling Secure PIN Entry on NetKey 3.0 Cards

Posted under Smartcards | Comments (0)

If you use the smartcard Cryptographic Provider provided by T-Systems for the card, you’ll notice that by default you are prompted to enter the PIN of the smartcard via the standard keyboard, even if you have class 2 reader, which has its own pin pad. This behavior can be easily changed with a small change in the registry. Just open the Windows Registry Editor and navigate to the node HKEY_LOCAL_MACHINE\SOFTWARE\T-Systems\CardMiniDriverTCOS3\MSCP and change the value of the field usePinPad from false to true. The next time you are required to enter the PIN, you are asked to do it via the pin pad of the smartcard reader. You might need to remove and insert the smartcard to get this to work.


Posted by Henning Krause on Friday, November 26, 2010 9:01 AM, last modified on Friday, November 26, 2010 9:01 AM
Permalink | Post RSSRSS comment feed

Fun with .NET 4 expressions

The other day I was tasked to write some code to synchronize data between two data stores. The entities were similar but not exactly the same. And I didn’t just want to synchronize all entries every time, but only if the source entity was different than the target entity. To simplify the comparison of each property, I wrote a small function which compared the values of one property of the source entity with the matching property on the target entity and updated it if it was different.

Let’s assume we have a simple entity class like this one:

class Contact
{
    public string Name { get; set; }
    public int Age { get; set; }
}

The method I write allows me to write this code to update a target entry with just a few lines of code:

var source = new Contact {Name = "Alice", Age = 42};
var target = new Contact();

if (UpdatePropertyIfChanged(source, target, contact => contact.Name, contact => contact.Name) | 
    UpdatePropertyIfChanged(source, target, contact => contact.Age, contact => contact.Age))
{
    Console.Out.WriteLine("Contact updated.");
    Console.Out.WriteLine("target.Name = {0}", target.Name);
    Console.Out.WriteLine("target.Age = {0}", target.Age);
}

The important method is the UpdatePropertyIfChanged method. It takes two entities, the source and the target instance. The third parameter is a lambda method which selects the property on the source instance and the last parameter selects the destination property on the target instance. To ensure that every property is checked, I used a logical or instead of a conditional or to ensure that every property is checked. If I had used the conditional or operator instead and the first property was different on both objects, the second property would not have been checked and updated.

Here is the body of the UpdatePropertyIfChanged method:

private static bool UpdatePropertyIfChanged<TSource, TProperty, TTarget>(TSource source, TTarget target, Func<TSource, TProperty> sourceSelector, Expression<Func<TTarget, TProperty>> targetSelector)
{
    var valueA = sourceSelector(source);
    var valueB = targetSelector.Compile()(target);

    if (EqualityComparer<TProperty>.Default.Equals(valueA, valueB)) return false;

    var setterMethod = CreateSetter(targetSelector);
    setterMethod(target, valueA);
    return true;
}

It’s pretty straigtforward, except for one details: Instead of a Func<TSource, TProperty> like the sourceSelector, the targetSelector is of type Expression<Func<TTarget, TProperty>>. The main difference is that an expression of type Func is already compiled and ready to be executed. In contrast, an expression of type Expression<Func> can be examined and manipulated at runtime.

The method executes these steps:

  1. Read the value of the property from the source entity by execute the sourceSelector expression
  2. Read the value of the property from the target entity by compiling and executing the targetSelector expression
  3. Compare the two values using the EqualityComparer<T>.Default comparer.
  4. If the two values are equal, just return false and abort the method.
  5. Convert the expression from the targetSelector expression to a setter expression
  6. Call the newly created expression with the value from the sourceSelector expression.

The ability to compile your own lambda expression has been introduced with .NET 3.5. But they were limited to reading properties and field. This feature has been improved with .NET 4.

Here is the body of the CreateSetter method:

private static Action<TInstance, TProperty> CreateSetter<TInstance, TProperty>(Expression<Func<TInstance, TProperty>> getterMethod)
{
    var memberExpression = getterMethod.Body as MemberExpression;

    if (memberExpression == null) throw new InvalidOperationException("GetterMethod must be a memberexpression");

    var instance = Expression.Parameter(typeof(TInstance));
    var parameter = Expression.Parameter(typeof(TProperty));
    var expression =
        Expression.Lambda<Action<TInstance, TProperty>>(
            Expression.Assign(
                Expression.MakeMemberAccess(instance, memberExpression.Member), parameter), new[] { instance, parameter });
    return expression.Compile();
}
This method expects an expression which maps an instance to a property of that instance. Based on this expression, a new expression is created, which sets that property to a specified value. The method returns this new expression in the form of an Action<TInstance, TProperty>.

Tags: ,

Technorati: ,

Posted by Henning Krause on Wednesday, November 24, 2010 4:52 PM, last modified on Tuesday, July 26, 2011 9:57 PM
Permalink | Post RSSRSS comment feed