Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

Friday, August 14, 2009

RSS Aggregator Webpart using Syndication

Scenario:
I read about Syndication sometime back after getting some hint from my friend Srini. RSS is now main stream requirement for getting updates from application / blogs and other sources. Microsoft always keep enhancing the dot net framework to make it more richer so they added support for syndication with dot net framework 3.5

Solution:
Here's a small webpart on how to use Syndication for reading RSS feeds from any site.

Steps:
1. Make sure you are using Framework 3.5
2. You need to add reference to System.ServiceModel.Web.dll

RSS WP

Code:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ServiceModel.Syndication;
using System.Web.UI;
using System.Xml;

namespace SyndicationWP
{
public class RSSWP : System.Web.UI.WebControls.WebParts.WebPart
{
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);

XmlReader reader = XmlReader.Create("http://feeds.feedburner.com/sandeepnahta");

SyndicationFeed feed = SyndicationFeed.Load(reader);
writer.WriteLine(feed.Title.Text);
writer.WriteLine("Items:");
foreach (SyndicationItem item in feed.Items)
{
writer.WriteLine("Title: {0}", item.Title.Text);
writer.WriteLine("Summary: {0}", ((TextSyndicationContent)item.Summary).Text);
}
writer.WriteLine("Press <enter> to quit...");
}
}
}
Possible Errors:
401 Unauthorized error if you are trying to consume a feed which you are not authorized to access. Most of sharepoint list RSS feed are protected.

Possible Improvements:
1. It can be generalized for any RSS feed links

Article:
SyndicationFeed Class

Saturday, June 27, 2009

Choosing a right port number for WCF Endpoint

Scenario:
While installing an endpoint for WCF Host service, we wanted to look for a port which is not being used by any other program for communication, to avoid any issues. Also we had many other WCF Host services in pipeline, so we wanted a standard way of choosing an unused port on our servers.

Solution:
PortQry was the solution. There is a command line version and a UI based version available for download from Microsoft.

PortQryV2.exe is a command-line utility that you can use to help troubleshoot TCP/IP connectivity issues. Portqry.exe runs on Windows 2000-based computers.The utility reports the port status of TCP and UDP ports on a computer you choose.

Download Command Line Utility

Download UI Based Utility

Examples :

The following command tries to resolve "reskit.com" to an IP address and then queries TCP port 25 on the corresponding host:

portqry -n reskit.com -p tcp -e 25
The following command tries to resolve "169.254.0.11" to a host name and then queries TCP ports 143,110, and 25 (in that order) on the host that you selected. This command also creates a log file (Portqry.log) that contains a log of the command that you ran and its output.
portqry -n 169.254.0.11 -p tcp -o 143,110,25 -l portqry.log
The following command tries to resolve my_server to an IP address and then queries the specified range of UDP ports (135-139) in sequential order on the corresponding host. This command also creates a log file (my_server.txt) that contains a log of the command that you ran and its output.
portqry -n my_server -p udp -r 135:139 -l my_server.txt
Article:
KB Article

Sunday, June 21, 2009

Exception Handling in WCF

Scenario:
Robust exception handling in key to any good system , specially with a new technology when you have lot of unknowns. WCF is easy to adopt but without a robust error handling its hard to debug in an environment where you have limited control.

Solution:
Here's a sample from MSDN , but important thing to note is the sequence in which exceptions are handled. Most specific once first and then the generic once.

Code:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;

public class Client
{
public static void Main()
{
// Picks up configuration from the configuration file.
SampleServiceClient wcfClient = new SampleServiceClient();
try
{
// Making calls.
Console.WriteLine("Enter the greeting to send: ");
string greeting = Console.ReadLine();
Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));
Console.WriteLine("Press ENTER to exit:");
Console.ReadLine();
}
catch (TimeoutException timeProblem)
{
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
wcfClient.Abort();
Console.ReadLine();
}
// Catch the contractually specified SOAP fault raised here as an exception.
catch (FaultException<GreetingFault> greetingFault)
{
Console.WriteLine(greetingFault.Detail.Message);
Console.Read();
wcfClient.Abort();
}
// Catch unrecognized faults. This handler receives exceptions thrown by WCF
// services when ServiceDebugBehavior.IncludeExceptionDetailInFaults
// is set to true.
catch (FaultException faultEx)
{
Console.WriteLine("An unknown exception was received. "
+ faultEx.Message
+ faultEx.StackTrace
);
Console.Read();
wcfClient.Abort();
}
// Standard communication fault handler.
catch (CommunicationException commProblem)
{
Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
Console.Read();
wcfClient.Abort();
}
}
}
Article:
MSDN

Follow me on Twitter

Wednesday, June 17, 2009

Calling WCF service from different domain

Scenario:
We had a requirement to call a WCF endpoint which was hosted in all together different domain. We had minimal trust between the domains. Creating direct proxy gave us SOAP Security Negotiation error.

This was Net TCP binding and we have Security mode Windows

Solution:
1. Create a local account on the server hosting the WCF Endpoint
2. Before opening the channel , set the client credentials as shown below.

Code:

//Connecting to WCF
var proxyClient = new MyWCFServiceClient();
proxyClient.ClientCredentials.Windows.ClientCredential.UserName = @"domain\username";
proxyClient.ClientCredentials.Windows.ClientCredential.Password = "sharepoint";
proxyClient.Open();
Follow me on Twitter

WCF Error : The requested upgrade is not supported

Scenario:
While trying to connect to WCF endpoint you got following error :

Error : The requested upgrade is not supported by 'net.tcp://servername:8080/ServiceName/mex'. This could be due to mismatched bindings (for example security enabled on the client and not on the server).


Solution:
-- Try to connect to WCF endpoint by adding a service reference using Visual Studio
-- Make sure service host is running.
-- Make sure the Configuration is same on both side ( server and client )
-- Try turning off security mode = None (case sensitive) as shown below (This may not be the best solution)

Code:

<bindings>
<netTcpBinding>
<binding name="MyService.Binding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" transactionFlow="false" transferMode="Buffered" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" listenBacklog="10" maxConnections="10">
<readerQuotas maxDepth="65536" maxStringContentLength="65536" maxArrayLength="65536" maxBytesPerRead="65536" maxNameTableCharCount="65536" />
<security mode ="None" />
</binding>
</netTcpBinding>
</bindings>

Follow me on Twitter

WCF Error : TCP Error Code 10061

Scenario:
While trying to connect to WCF endpoint you got following error :
Error : Could not connect to net.tcp://servername:8080/ServiceName. The connection attempt lasted for a time span of 00:00:01.*. TCP error code 10061: No connection could be made because the target machine actively refused it 198.0.0.1:8080.

Solution:
-- Try to connect to WCF endpoint by adding a service reference using Visual Studio
-- Make sure service host is running.
-- Make sure the Configuration is same on both side ( server and client )
-- Try turning off security mode = None (case sensitive) as shown below
-- In case there is no trust between domain , you might need to set firewall exception to open the port for communication

Code:

<bindings>
<netTcpBinding>
<binding name="MyService.Binding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" transactionFlow="false" transferMode="Buffered" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" listenBacklog="10" maxConnections="10">
<readerQuotas maxDepth="65536" maxStringContentLength="65536" maxArrayLength="65536" maxBytesPerRead="65536" maxNameTableCharCount="65536" />
<security mode ="None" />
</binding>
</netTcpBinding>
</bindings>

Follow me on Twitter

Friday, April 10, 2009

WCF turn on IncludeExceptionDetailInFaults

Error: The server was unable to process the request due to an internal error.
For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the
configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.System.Exception {System.ServiceModel.FaultException}

Reason/Solution:
When any kind of error occur calling a WCF endpoint from client, client will receive a generic message ( as given above ) for security reason.

If you want to see the full details of the error, you need to change the app.config file for the WCF Host to include full exception details while sending it to clients.

Host App.Config:

<configuration>
<system.serviceModel>
<services>
<!-- Step 1. Add a behaviorConfiguration attribute -->
<service
name="Microsoft.WCF.Documentation.SampleService"
behaviorConfiguration="metadataAndDebug">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/SampleService" />
</baseAddresses>
</host>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<!-- Step 2. Add a new behavior below.-->
<behavior name="metadataAndDebug">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<!-- Step 3. Add a <serviceDebug> element -->
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Article:MSDN


This setting is only recommended for DEV purpose.

Using Generic List in WCF

Scenario:
I wanted to store few documentIDs in my DataMember. I thought of using Generic List, so far so good but when adding the service reference from my client application, I noticed that Generic List got converted to string[] and while compiling I got the following error

Cannot implicitly convert type 'string[]' to System.Collections.Generic.List'

Workaround:
The representation of a List is equivalent to the representation of a ArrayList. So it will just work if you use the Arraylist at the client side

Solution:
Right click the Service reference > Configure Service Reference > Select 'System.Collection.Generic.List' from Collection type drop down menu.

But i wanted to still use Generic List, so this is how i did it.
Here's the code.

IService1.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

using System.Collections;

namespace TestWCF
{
[ServiceContract]
public interface IService1
{
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}

[DataContract]
public class CompositeType
{
private List<string> lists;
[DataMember]
public List<string> Lists
{
get { return lists; }
set { lists = value; }
}
}
}
Service1.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace TestWCF
{
public class Service1 : IService1
{
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
composite.Lists = new List<string>();
composite.Lists.Add("D");

return composite;
}
}
}
Code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TestWCFClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
ServiceReference1.CompositeType composite = new ServiceReference1.CompositeType() ;
ServiceReference1.CompositeType composite2 = new ServiceReference1.CompositeType() ;

ServiceReference1.Service1Client sc = new ServiceReference1.Service1Client();
composite2 = sc.GetDataUsingDataContract(composite);
MessageBox.Show(composite2.Lists.Count.ToString());
}
}
}

Using Hashtable in WCF

Scenario:
I wanted to store some key value pair information in my DataMember. I thought of using Hashtable as DataMember, so far so good but when adding the service reference from my client application, I noticed that Hashtable got converted to Dictionary and while compiling I got the following error

Cannot implicitly convert type 'System.Collections.Generic.Dictionary' to 'System.Collections.Hashtable'

Workaround:
The representation of a Hashtable in the wire is equivalent to the representation of a dictionary. So it will just work if you use the Dictionary at the client side

Solution:
Right click the Service reference > Configure Service Reference > Select 'System.Collection.Hashtable' from Dictionary collection type drop down menu.

But i wanted to still use Hashtable, so this is how i did it.
Here's the code.

IService1.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

using System.Collections;

namespace TestWCF
{
[ServiceContract]
public interface IService1
{
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}

[DataContract]
public class CompositeType
{
private Hashtable doc;
[DataMember]
public Hashtable Doc
{
get { return doc; }
set { doc = value; }
}
}
}
Service1.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace TestWCF
{
public class Service1 : IService1
{
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
composite.Doc = new Hashtable();
composite.Doc.Add("A","B");

return composite;
}
}
}
I created a Windows Form application to test the WCF service.
Form1.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TestWCFClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
ServiceReference1.CompositeType composite = new ServiceReference1.CompositeType() ;
ServiceReference1.CompositeType composite2 = new ServiceReference1.CompositeType() ;

ServiceReference1.Service1Client sc = new ServiceReference1.Service1Client();
composite2 = sc.GetDataUsingDataContract(composite);
MessageBox.Show(composite2.Doc["A"].ToString());
}
}
}

WCF : Already a listener on the IP endpoint

Scenario:
While testing my WCF service using netTCP binding, I got the following error.

Error:Unhandled Exception: System.ServiceModel.AddressAlreadyInUseException: There is already a listener on IP endpoint 0.0.0.0:9000. Make sure that you are not trying to use this endpoint multiple times in your application and that there are no other applications listening on this endpoint. ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted

Reason:
NetTcp Port Sharing is a Windows Communication Foundation (WCF) feature that is similar to IIS and allows multiple network applications to share a single port. The NetTcp Port Sharing Service accepts connections using the net.tcp protocol and forwards messages based on their destination address.But NetTcp Port Sharing Service is not enabled by default.

Solution:
1. You can also use TCPView to check what process that is holding the port open.
2. Check using following command
netstat -a | find "portno"
3. Try restarting the service or server
4. Try configuring the service on different port number
5. You can try enabling port sharing ( require NetTcp Port Sharing Service running)

Code:


<system.serviceModel>
<bindings>
<netTcpBinding name="customBinding"
portSharingEnabled="true" />
<services>
<service name="MyService">
<endpoint address="net.tcp://localhost/MyService"
binding="netTcpBinding"
contract="IMyService"
bindingConfiguration="customBinding" />
</service>
</services>
</system.serviceModel>
Article:
TCP View

Thursday, April 9, 2009

WCF Errors

Scenario:
Past week I was working on a new WCF service and encountered following errors

Error 1:
The maximum array length quota (16384) has been exceeded while reading XML data. This quota may be increased by changing the MaxArrayLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.'. Please see InnerException for more details.

Error 2:
The maximum nametable character count quota (16384) has been exceeded while reading XML data. The nametable is a data structure used to store strings encountered during XML processing - long XML documents with non-repeating element names, attribute names and attribute values may trigger this quota. This quota may be increased by changing the MaxNameTableCharCount property on the XmlDictionaryReaderQuotas object used when creating the XML reader

Error 3:
The formatter threw an exception while trying to deserialize the message: Error in deserializing body of request message for operation 'XYZ'. The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader

Solution:
All the above errors are related to the way Server and Client side binding configuration are set. Make sure you have same values on both side.

Error 1 : MaxArrayLength default value is 16384 , try increasing it to a bigger value.

Error 2 : MaxNameTableCharCount default value is 16384 , try increasing it to a bigger value.

Error 3 : MaxStringContentLength default value is 8192, try increasing it to a bigger value.