Normally, there are a few steps we have to follow for creating or consuming a WCF service.
- Server side - create a new ServiceHost for new WCF service.
- Client side - make sure the correct client name is setup in client source.
- Make sure - make sure that the .config files of both client/server side are set up properly.
Any spelling error could waste a couple of hours of investigation. I was really really tired of this job until I found some code on stackoverflow recently. Unfortunately, I could not find that thread again. Here I have attached my code instead.
- protected Dictionary<Type, object> GetBehaviors(string name)
- {
- if (!_behaviorCache.ContainsKey(name))
- {
- BehaviorsSection behaviorData = ConfigurationManager.GetSection("system.serviceModel/behaviors") as BehaviorsSection;
- List<BehaviorExtensionElement> behaviors = new List<BehaviorExtensionElement>();
- if (behaviorData.ServiceBehaviors.ContainsKey(name))
- {
- behaviorData.ServiceBehaviors[name].All(e =>
- {
- behaviors.Add(e);
- return true;
- });
- }
- if (behaviorData.EndpointBehaviors.ContainsKey(name))
- {
- behaviorData.EndpointBehaviors[name].All(e =>
- {
- behaviors.Add(e);
- return true;
- });
- }
- _behaviorCache.Add(name, behaviors.ToDictionary(e => e.BehaviorType, e => createBehavior(e)));
- }
- return _behaviorCache[name];
- }
- private object createBehavior(BehaviorExtensionElement element)
- {
- return element.GetType().GetMethod("CreateBehavior", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
- .Invoke(element, new object[0] { });
- }
- private ServiceHost getServiceHost(Type serviceType, Type interfaceType)
- {
- WebServiceAttribute attribute = interfaceType.GetCustomAttribute<WebServiceAttribute>();
- if (attribute == null)
- throw new ArgumentException("WebService attribute is missing");
- string serviceUrl = GetServiceUrl(attribute, "localhost");
- ServiceHost serviceHost = new ServiceHost(serviceType, new Uri(serviceUrl));
- var serviceMetadataBehavior = new ServiceMetadataBehavior();
- serviceHost.Description.Behaviors.Add(serviceMetadataBehavior);
- // add behaviors
- Dictionary<Type, object> behaviors = GetBehaviors(attribute.BehaviorConfiguration);
- behaviors.All(e =>
- {
- serviceHost.Description.Behaviors.Remove(e.Key);
- serviceHost.Description.Behaviors.Add(e.Value as IServiceBehavior);
- return true;
- });
- serviceHost.AddServiceEndpoint(interfaceType, GetBinding(attribute), serviceUrl);
- return serviceHost;
- }
- public class WebServiceAttribute : Attribute
- {
- public string RelativePath { get; set; }
- public Type BaseBinding { get; set; }
- public string CustomBinding { get; set; }
- public string BehaviorConfiguration { get; set; }
- public bool UseCallback { get; set; }
- private static readonly string DEFAULT_BEHAVIOR = "customBehavior";
- private static readonly string DEFAULT_BINDING = "customWsHttpBinding";
- public WebServiceAttribute()
- {
- UseCallback = false;
- BaseBinding = typeof(WSHttpBinding);
- CustomBinding = DEFAULT_BINDING;
- BehaviorConfiguration = DEFAULT_BEHAVIOR;
- }
- }
- [ServiceContract]
- [WebService(RelativePath = "/myapp/SimpleService/")]
- public interface ISimpleService
- {
- [OperationContract]
- void Speak(string words);
- }
In the attached sample solution (by VS2015), you can find that the class WebServiceServerProber is used to find all available WCF services in a particular module and create ServiceHost for them; while the WebServiceSingleClientProber class is used in the client to create ChannelFactory.
We have saved hundreds of lines in .config file in our project. I hope it will help you! Let me know if you have any questions.
Join the conversation! Your thoughts help the community grow.