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.
  1. protected Dictionary<Type, object> GetBehaviors(string name)
  2. {
  3. if (!_behaviorCache.ContainsKey(name))
  4. {
  5. BehaviorsSection behaviorData = ConfigurationManager.GetSection("system.serviceModel/behaviors") as BehaviorsSection;
  6. List<BehaviorExtensionElement> behaviors = new List<BehaviorExtensionElement>();
  7. if (behaviorData.ServiceBehaviors.ContainsKey(name))
  8. {
  9. behaviorData.ServiceBehaviors[name].All(e =>
  10. {
  11. behaviors.Add(e);
  12. return true;
  13. });
  14. }
  15. if (behaviorData.EndpointBehaviors.ContainsKey(name))
  16. {
  17. behaviorData.EndpointBehaviors[name].All(e =>
  18. {
  19. behaviors.Add(e);
  20. return true;
  21. });
  22. }
  23. _behaviorCache.Add(name, behaviors.ToDictionary(e => e.BehaviorType, e => createBehavior(e)));
  24. }
  25. return _behaviorCache[name];
  26. }
  27. private object createBehavior(BehaviorExtensionElement element)
  28. {
  29. return element.GetType().GetMethod("CreateBehavior", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
  30. .Invoke(element, new object[0] { });
  31. }
What is it? It creates a list of behaviors by given behavior name, so a ServiceHost could be created as below.
  1. private ServiceHost getServiceHost(Type serviceType, Type interfaceType)
  2. {
  3. WebServiceAttribute attribute = interfaceType.GetCustomAttribute<WebServiceAttribute>();
  4. if (attribute == null)
  5. throw new ArgumentException("WebService attribute is missing");
  6. string serviceUrl = GetServiceUrl(attribute, "localhost");
  7. ServiceHost serviceHost = new ServiceHost(serviceType, new Uri(serviceUrl));
  8. var serviceMetadataBehavior = new ServiceMetadataBehavior();
  9. serviceHost.Description.Behaviors.Add(serviceMetadataBehavior);
  10. // add behaviors
  11. Dictionary<Type, object> behaviors = GetBehaviors(attribute.BehaviorConfiguration);
  12. behaviors.All(e =>
  13. {
  14. serviceHost.Description.Behaviors.Remove(e.Key);
  15. serviceHost.Description.Behaviors.Add(e.Value as IServiceBehavior);
  16. return true;
  17. });
  18. serviceHost.AddServiceEndpoint(interfaceType, GetBinding(attribute), serviceUrl);
  19. return serviceHost;
  20. }
If all the information could be fetched from the given attribute, is it enough for service creation? Yes!
  1. public class WebServiceAttribute : Attribute
  2. {
  3. public string RelativePath { get; set; }
  4. public Type BaseBinding { get; set; }
  5. public string CustomBinding { get; set; }
  6. public string BehaviorConfiguration { get; set; }
  7. public bool UseCallback { get; set; }
  8. private static readonly string DEFAULT_BEHAVIOR = "customBehavior";
  9. private static readonly string DEFAULT_BINDING = "customWsHttpBinding";
  10. public WebServiceAttribute()
  11. {
  12. UseCallback = false;
  13. BaseBinding = typeof(WSHttpBinding);
  14. CustomBinding = DEFAULT_BINDING;
  15. BehaviorConfiguration = DEFAULT_BEHAVIOR;
  16. }
  17. }
So, how do we use it? Just apply it on web interface, that's all.
  1. [ServiceContract]
  2. [WebService(RelativePath = "/myapp/SimpleService/")]
  3. public interface ISimpleService
  4. {
  5. [OperationContract]
  6. void Speak(string words);
  7. }
So, with the help of WebServiceAttribute and the above codes, we are able to create a Service Host via .NET Reflection. Also, it is also possible to create a WCF Service client since this attribute contains all the information for ChannelFactory<> creation.
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.