An error that comes up when moving code which calls a WCF service from development to production:
"Custom tool warning: Cannot import wsdl:portType"
It also details a number of "custom tool" errors.
The problem stems from when I pull some Visual Studio Solution code over from my development lab, delete the service references in the projects in the solution (which point to the WCF service in the devlab) and re-add them as service references pointing to the WCF service in the production lab.
Evidently a lot is going on during the creation of these service references -- when Googling for information on it other users recommend completely shutting down and restarting Visual Studio; the best recommendation comes from stackoverflow and recommends re-adding these references while specifying not to reuse types in reference assemblies:
http://stackoverflow.com/questions/1872865/what-does-this-wcf-error-mean-custom-tool-warning-cannot-import-wsdlporttype
http://www.lukepuplett.com/2010/07/note-to-self-don-let-wcf-svcutil-reuse.html
Saturday, March 2, 2013
Thursday, February 28, 2013
"The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element."
This happened when I was sending large chunks of data through a WCF service -- by default it seems that the service is configured not accept anything over a certain size, probably as a security measure.
Overriding it is done by adding a "readerQuotas" section:
<bindings>
<basicHttpBinding>
<binding maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
Drawn from this blog:
http://www.megustaulises.com/2012/04/wcf-common-error-messages-tips-and.html?_escaped_fragment_="
A word of caution, though -- in most examples I found in Google there was an admonition to add a "name" attribute to the "binding" element (e.g., http://stackoverflow.com/questions/3068076/wcf-service-the-maximum-array-length-quota-16384-has-been-exceeded) and if you use the "Edit WCF Configuration" utility in Visual Studio 2010 it'll actually say there's an error when it senses that the "name" attribute is missing.
This has confused more people than just me -- see https://go4answers.webhost4life.com/Example/maximum-array-length-quota-16384-36456.aspx, especially "Answer 6". It seems that if the "name" attribute is left out then the change is made to the global binding definition if the WCF project is .NET 4.0+.
The confusion would seem to come from an improvement in the structure of WCF config files introduced in .NET 4.0/4.5 as a "simplification" feature, documented in http://msdn.microsoft.com/en-us/library/hh309266.aspx
Overriding it is done by adding a "readerQuotas" section:
<bindings>
<basicHttpBinding>
<binding maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
Drawn from this blog:
http://www.megustaulises.com/2012/04/wcf-common-error-messages-tips-and.html?_escaped_fragment_="
A word of caution, though -- in most examples I found in Google there was an admonition to add a "name" attribute to the "binding" element (e.g., http://stackoverflow.com/questions/3068076/wcf-service-the-maximum-array-length-quota-16384-has-been-exceeded) and if you use the "Edit WCF Configuration" utility in Visual Studio 2010 it'll actually say there's an error when it senses that the "name" attribute is missing.
This has confused more people than just me -- see https://go4answers.webhost4life.com/Example/maximum-array-length-quota-16384-36456.aspx, especially "Answer 6". It seems that if the "name" attribute is left out then the change is made to the global binding definition if the WCF project is .NET 4.0+.
The confusion would seem to come from an improvement in the structure of WCF config files introduced in .NET 4.0/4.5 as a "simplification" feature, documented in http://msdn.microsoft.com/en-us/library/hh309266.aspx
Tuesday, February 26, 2013
WCF Error: "This collection already contains an address with scheme http"
This comes when pushing a new WCF service up from development to production -- it'll work fine in dev, then fail with this message in production:
"This collection already contains an address with scheme http"
The solution is to update the web.config section of the IIS hosted WCF service and the app.config section of the library used by WCF and is described in a couple different links:
I wish I knew WCF well enough to say what the fix is actually doing but at present I can't quite say what's going on -- I'm still learning it and, once I find out what my problem is, I'll add to this post. In the meantime, I've just got to get this running.
"This collection already contains an address with scheme http"
The solution is to update the web.config section of the IIS hosted WCF service and the app.config section of the library used by WCF and is described in a couple different links:
In my case, I put this code right after the <servicemodel> tag:
<servicemodel>
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
 <add prefix=http://mignysm95bakpv.nysemail.nyenet"/>
<baseAddressPrefixFilters>
</serviceHostingEnvironment>
....
etc. etc. etc. ....
</servicemodel>
<servicemodel>
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
 <add prefix=http://mignysm95bakpv.nysemail.nyenet"/>
<baseAddressPrefixFilters>
</serviceHostingEnvironment>
....
etc. etc. etc. ....
</servicemodel>
I wish I knew WCF well enough to say what the fix is actually doing but at present I can't quite say what's going on -- I'm still learning it and, once I find out what my problem is, I'll add to this post. In the meantime, I've just got to get this running.
Tuesday, January 15, 2013
"Could not find endpoint element with name ..." WCF error
I developed a windows service which periodically polls a WCF server for information -- I added a service reference to the project which provided a proxy for a "ProvisioningClient" object. The could would instantiate this object and then perform tasks:
using (ProvisioningClient client = new ProvisioningClient("basic")
{
// Do stuff
}
The way I create windows services is to first create a DLL that performs all of the work and then load and call it from a C# windows project.
For debugging, though, I put together a simple Windows form test harness (just a single form in a project called "Service Impersonator") with a single "Start DLL" button which loads the DLL and lets me interactively debug the DLL code.
The program would consistently fail on the "using" statement above, though, with a message:
Could not find endpoint element with the name 'basic' and contract 'ExchangeProvisioningServiceReference.IExchangeProvisioning' in the ServiceModel client configuration section...
I'd check the APP.CONFIG file in the DLL and there was indeed an endpoint element called 'basic' following that very contract; reviewing the WEB.CONFIG file of the WCF service showed that the syntax matched perfectly.
Since the code failed in the DLL and the error pointed to the APP.CONFIG file, that's where I kept looking and puzzling. The problem was not there but in the Winform test harness project: it was a very simple project which just called the DLL but for some reason the DLL looked for an APP.CONFIG file in the .EXE file calling it and, not finding one, gave me that message.
Adding a service reference to the Winform test harness project that called the DLL resolved the problem. I don't understand why the DLL doesn't look at its own APP.CONFIG file but that's the way it is.
using (ProvisioningClient client = new ProvisioningClient("basic")
{
// Do stuff
}
The way I create windows services is to first create a DLL that performs all of the work and then load and call it from a C# windows project.
For debugging, though, I put together a simple Windows form test harness (just a single form in a project called "Service Impersonator") with a single "Start DLL" button which loads the DLL and lets me interactively debug the DLL code.
The program would consistently fail on the "using" statement above, though, with a message:
Could not find endpoint element with the name 'basic' and contract 'ExchangeProvisioningServiceReference.IExchangeProvisioning' in the ServiceModel client configuration section...
I'd check the APP.CONFIG file in the DLL and there was indeed an endpoint element called 'basic' following that very contract; reviewing the WEB.CONFIG file of the WCF service showed that the syntax matched perfectly.
Since the code failed in the DLL and the error pointed to the APP.CONFIG file, that's where I kept looking and puzzling. The problem was not there but in the Winform test harness project: it was a very simple project which just called the DLL but for some reason the DLL looked for an APP.CONFIG file in the .EXE file calling it and, not finding one, gave me that message.
Adding a service reference to the Winform test harness project that called the DLL resolved the problem. I don't understand why the DLL doesn't look at its own APP.CONFIG file but that's the way it is.
Oddity when working with event logs
During development I often create then delete custom Windows event logs for my applications.
A problem arises when I do something like delete and then recreate an event log and event source in order to correct a spelling or something like that ... I'm able to delete the old log and the source but when I recreate the new (correctly spelled) log and source I will see the new log appears but I can't seem to write to it anymore.
There's a peculiarity with Windows event logs -- if you delete them and then recreate them, you need to reboot the computer for writing to the event log to begin behaving correctly again. See:
http://stackoverflow.com/questions/1901312/eventlog-createeventsource-is-not-creating-a-custom-log
and
http://msdn.microsoft.com/en-us/library/2awhba7a.aspx (about half way down the page)
A problem arises when I do something like delete and then recreate an event log and event source in order to correct a spelling or something like that ... I'm able to delete the old log and the source but when I recreate the new (correctly spelled) log and source I will see the new log appears but I can't seem to write to it anymore.
There's a peculiarity with Windows event logs -- if you delete them and then recreate them, you need to reboot the computer for writing to the event log to begin behaving correctly again. See:
http://stackoverflow.com/questions/1901312/eventlog-createeventsource-is-not-creating-a-custom-log
and
http://msdn.microsoft.com/en-us/library/2awhba7a.aspx (about half way down the page)
Sunday, January 13, 2013
Exchange 2007 Admin in C# on W2008R2 using Visual Studio 2010
I wrote a service which performed Exchange 2007 administration tasks which performed successfully for years running on a Windows 2003 R2 server. Recently we went through an upgrade to W2008R2 and Exchange 2010 and I began upgrading the service to use the new and very different PowerShell snap-in for Exchange 2010.
Suddenly we partially reversed course, however, and decided to stay with Exchange 2007 while continuing the upgrade to W2008R2 for the server OS.
So I am having to rewrite my original windows service code to run on 64-bit W2008R2 machines. I remembered that when I initially wrote the service I had several issues getting Visual Studio (then VS2005, now VS2010), the PowerShell runspace, the Exchange 2007 Administration PSSnapin, and the bit-iness of the machine to agree and to let me do what I needed to do. I remembered that these problems took days to resolve.
I would run into persistent problems getting my C# code to recognize the snap-in, to use the correct version of the System.Management.Automation tools, etc. which would be evidenced with errors like:
"No snap-ins have been registered for Windows PowerShell version 2"
"Could not load file or assembly 'Microsoft.Exchange.PowerShell.Configuration, Version=14.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified."
"MSCorlib.dll is compiled for wrong processor"
Googling around it is clear that this is a common problem and is a bit-iness issue between all the different entities and all of them must be lined up in the right way to make things work.
I established a set of steps that worked for me in a virgin test environment on a virtual machine; I then took it into my production environment (which had suffered installs and uninstalls of the Exchange 2007 and 2010 management tools) and tried it again and it worked.
The steps I followed to get it to work were:
01) Install the Exchange 2007 management tools from the Exchange 2007 SP1 distribution DVD onto the server
02) Update the management tools to service pack 3 (by downloading the Exchange 2007 SP3 download from Microsoft)
03) Start Visual Studio 2010 and create a console application.
04) Create a class in the console app to hold the Exchange 2007 Admin PowerShell wrapper written by Nick Smith (at http://knicksmith.blogspot.com/2007/03/managing-exchange-2007-recipients-with.html)
05) Have the main() method of the program.cs file call Nick Smith's exchange wrapper, e.g.:
static void main(string[] args)
{
// Do a simple dump of mailbox names
ExchangeManagementShellWrapper ems = ExchangeManagementShellWrapper.Instance;
ICollection results;
results = ems.Runsp
aceInvoke("Get-Mailbox");
foreach (PSObject item in results)
{
Console.WriteLine(item.Members["Name"].Value.ToString());
}
}
06) Make sure the project's set to build using .NET framework 3.5.
07) Make sure the project's set to build to the x64 platform
08) Make sure there's a reference to "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Management.dll"
09) Make sure there's a reference to "C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll"
That should do it. The Exchange 2007 PowerShell cmdlets are only installed as x64 and the System Automation dlls only seemed to work for me if the code is targeted towards .NET 3.5, not .NET 4.0 (which my VS editor defaulted to).
I'll include the source code for the project if there's any interest in that.
Suddenly we partially reversed course, however, and decided to stay with Exchange 2007 while continuing the upgrade to W2008R2 for the server OS.
So I am having to rewrite my original windows service code to run on 64-bit W2008R2 machines. I remembered that when I initially wrote the service I had several issues getting Visual Studio (then VS2005, now VS2010), the PowerShell runspace, the Exchange 2007 Administration PSSnapin, and the bit-iness of the machine to agree and to let me do what I needed to do. I remembered that these problems took days to resolve.
I would run into persistent problems getting my C# code to recognize the snap-in, to use the correct version of the System.Management.Automation tools, etc. which would be evidenced with errors like:
"No snap-ins have been registered for Windows PowerShell version 2"
"Could not load file or assembly 'Microsoft.Exchange.PowerShell.Configuration, Version=14.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified."
"MSCorlib.dll is compiled for wrong processor"
Googling around it is clear that this is a common problem and is a bit-iness issue between all the different entities and all of them must be lined up in the right way to make things work.
I established a set of steps that worked for me in a virgin test environment on a virtual machine; I then took it into my production environment (which had suffered installs and uninstalls of the Exchange 2007 and 2010 management tools) and tried it again and it worked.
The steps I followed to get it to work were:
01) Install the Exchange 2007 management tools from the Exchange 2007 SP1 distribution DVD onto the server
02) Update the management tools to service pack 3 (by downloading the Exchange 2007 SP3 download from Microsoft)
03) Start Visual Studio 2010 and create a console application.
04) Create a class in the console app to hold the Exchange 2007 Admin PowerShell wrapper written by Nick Smith (at http://knicksmith.blogspot.com/2007/03/managing-exchange-2007-recipients-with.html)
05) Have the main() method of the program.cs file call Nick Smith's exchange wrapper, e.g.:
static void main(string[] args)
{
// Do a simple dump of mailbox names
ExchangeManagementShellWrapper ems = ExchangeManagementShellWrapper.Instance;
ICollection
results = ems.Runsp
aceInvoke("Get-Mailbox");
foreach (PSObject item in results)
{
Console.WriteLine(item.Members["Name"].Value.ToString());
}
}
06) Make sure the project's set to build using .NET framework 3.5.
07) Make sure the project's set to build to the x64 platform
08) Make sure there's a reference to "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Management.dll"
09) Make sure there's a reference to "C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll"
That should do it. The Exchange 2007 PowerShell cmdlets are only installed as x64 and the System Automation dlls only seemed to work for me if the code is targeted towards .NET 3.5, not .NET 4.0 (which my VS editor defaulted to).
I'll include the source code for the project if there's any interest in that.
Sunday, November 4, 2012
MS Active Directory "accountExpires" value -- getting and setting it
If you use ADSI to get a DirectoryEntry object from Active Directory you'll find that the "accountExpires" property is stored as a DateTime variable in a large integer format called the IADsLargeInteger format (http://msdn.microsoft.com/en-us/library/windows/desktop/aa706037%28v=vs.85%29.aspx). The format represents a date as an 8 byte variable indicating the number of 100-nanosecond intervals since January 1, 1601 (look up the Wikipedia article for this date if you're curious as to why it's used).
Converting this format into a standard C# DateTime value requires a 2-step process of converting the IADsLargeInteger into a standard C# long value, then converting this long value into a C# date time.
I found several (incorrect) versions of functions to accomplish this on the Internet but the best functioning version (derived from MSDN's articles on accountExpires, IADsLargeInteger, and DateTime conversions) comes from Tobi's 'tips' 4 and 5 in his notes on Active Directory (http://www.fsmpi.uni-bayreuth.de/~dun3/archives/category/it/programming/active-directory):
First, convert the IADsLargeInteger into a long:
private static long ConvertLargeIntegerToLong(object largeInteger)
{
Type type = largeInteger.GetType();
int highPart = (int)type.InvokeMember("HighPart", BindingFlags.GetProperty, null, largeInteger, null);
int lowPart = (int)type.InvokeMember("LowPart", BindingFlags.GetProperty | BindingFlags.Public, null, largeInteger, null);
return (long)highPart <<32 lowpart="lowpart" p="p" uint="uint">}
Then use this to convert the long into a DateTime. Note that the DateTime is stored in UTC format -- luckily .NET has the "FromFileTimeUTC()" method ready-made to handle this for us:
object accountExpires = DirectoryEntryHelper.GetAdObjectProperty(directoryEntry, "accountExpires");
var asLong = ConvertLargeIntegerToLong(accountExpires);
if (asLong == long.MaxValue || asLong <= 0 ||
DateTime.MaxValue.ToFileTime() <= asLong)
{
return DateTime.MaxValue;
}
else
{
return DateTime.FromFileTimeUtc(asLong);
}
Note 1: "Magic values" in the accountExpires attribute
Two values in the accountExpires attribute indicate that the account is set to "Never Expires." These are zero (0) and 9223372036854775807 (0x7FFFFFFFFFFFFFFF).
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms675098%28v=vs.85%29.aspx
Note 2: Getting the accountExpires attribute from an ADSI "DirectorySearcher" search result
This is very important (and delayed me quite a while when I didn't take it into account).
If you pull an account's DirectoryEntry using ADSI the 'accountExpires' property is returned as an IADsLargeInteger, but if you get it as a search result using "DirectorySearcher" the property will be presented as a standard long. No translation from IADsLongInteger are required, you'll just need to do the translation from long to DateTime ("step 2" above).
See http://forums.asp.net/t/999913.aspx and comments by MVP "Dunry" for a useful discussion of this.
Converting this format into a standard C# DateTime value requires a 2-step process of converting the IADsLargeInteger into a standard C# long value, then converting this long value into a C# date time.
I found several (incorrect) versions of functions to accomplish this on the Internet but the best functioning version (derived from MSDN's articles on accountExpires, IADsLargeInteger, and DateTime conversions) comes from Tobi's 'tips' 4 and 5 in his notes on Active Directory (http://www.fsmpi.uni-bayreuth.de/~dun3/archives/category/it/programming/active-directory):
First, convert the IADsLargeInteger into a long:
private static long ConvertLargeIntegerToLong(object largeInteger)
{
Type type = largeInteger.GetType();
int highPart = (int)type.InvokeMember("HighPart", BindingFlags.GetProperty, null, largeInteger, null);
int lowPart = (int)type.InvokeMember("LowPart", BindingFlags.GetProperty | BindingFlags.Public, null, largeInteger, null);
return (long)highPart <<32 lowpart="lowpart" p="p" uint="uint">}
Then use this to convert the long into a DateTime. Note that the DateTime is stored in UTC format -- luckily .NET has the "FromFileTimeUTC()" method ready-made to handle this for us:
object accountExpires = DirectoryEntryHelper.GetAdObjectProperty(directoryEntry, "accountExpires");
var asLong = ConvertLargeIntegerToLong(accountExpires);
if (asLong == long.MaxValue || asLong <= 0 ||
DateTime.MaxValue.ToFileTime() <= asLong)
{
return DateTime.MaxValue;
}
else
{
return DateTime.FromFileTimeUtc(asLong);
}
Note 1: "Magic values" in the accountExpires attribute
Two values in the accountExpires attribute indicate that the account is set to "Never Expires." These are zero (0) and 9223372036854775807 (0x7FFFFFFFFFFFFFFF).
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms675098%28v=vs.85%29.aspx
Note 2: Getting the accountExpires attribute from an ADSI "DirectorySearcher" search result
This is very important (and delayed me quite a while when I didn't take it into account).
If you pull an account's DirectoryEntry using ADSI the 'accountExpires' property is returned as an IADsLargeInteger, but if you get it as a search result using "DirectorySearcher" the property will be presented as a standard long. No translation from IADsLongInteger are required, you'll just need to do the translation from long to DateTime ("step 2" above).
See http://forums.asp.net/t/999913.aspx and comments by MVP "Dunry" for a useful discussion of this.
Subscribe to:
Posts (Atom)