Need help on WCF Design - wcf

I have a project written in C++ COM+(Server Side) and VB6(Client Side). We have decided to redesign the project in WCF Architecture using C# language.
As a part of my learning, I have created a simple test Project in WCF which is below.
The idea is that when the WBWindowsService is started, it should create a TASWB object and then Run a Thread to Calculate the Weight. So when a client call the Getweight() method, it should be able to receive the weight calculated by the thread.
But when I tried, I am always getting 0 which is the initial value. So I think what i am missing is how to manage the objects in WCF.
Kindly Help. Thanks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration;
using System.Configuration.Install;
namespace TASWeighBridge
{
public class WBWindowsService : ServiceBase
{
public ServiceHost serviceHost = null;
private TASWB obj;
public WBWindowsService()
{
// Name the Windows Service
ServiceName = "WBWindowsService";
}
public static void Main()
{
ServiceBase.Run(new WBWindowsService());
}
// Start the Windows service.
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
obj = new TASWB();
obj.RunThread();
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(TASWB));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
}
}
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration;
using System.Configuration.Install;
namespace TASWeighBridge
{
// Define a service contract.
[ServiceContract]
public interface IWeighBridge
{
[OperationContract]
double Getweight();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration;
using System.Configuration.Install;
using System.Threading;
namespace TASWeighBridge
{
// Implement the ICalculator service contract in a service class.
public class TASWB : IWeighBridge
{
private double weight = 0;
public void RunThread()
{
Thread T1 = new Thread(new ThreadStart(CalcWeight));
T1.Start();
//T1.Join();
}
private void CalcWeight()
{
Thread.Sleep(1000);
weight = weight + 1;
}
public double Getweight()
{
return weight;
}
}
}
App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel> <services>
<!-- This section is optional with the new configuration model
introduced in .NET Framework 4. -->
<service name="TASWeighBridge.TASWB"
behaviorConfiguration="TASWBBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/TASWBService"/>
</baseAddresses>
</host>
<!-- this endpoint is exposed at the base address provided by host: http://localhost:8000/TASWBService -->
<endpoint address=""
binding="wsHttpBinding"
contract="TASWeighBridge.IWeighBridge" />
<!-- the mex endpoint is exposed at http://localhost:8000/TASWBService/mex -->
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TASWBBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

Related

My WCF Implementation class reference is not showing up in Windows Service

My Windows Service is now showing up my WCF Implementation class.
Hence when I start my service it is giving me error of "ServiceHost only supports class service types."
Here's my code:
try
{
Console.WriteLine("Testing 1");
WCFEmailEventLog.WriteEntry("My service started");
System.Diagnostics.Debugger.Break();
// Create a ServiceHost
// provide the base address.
serviceHost = new ServiceHost(typeof(TestBulkEmailService.BulkEmailService), new Uri("http://localhost/TestBulkEmailService/TestBulkEmailService.svc") );
WCFEmailEventLog.WriteEntry("After Service host ");
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
In the above code the typeOf(TestBulkEmailService.BulkEmailService) does not show the Implementation class BulkEmailService and only shows my WCF Contract IBulkEmailService.
What am I doing wrong?
Here is my app.config file:
<services>
<service name="WW.Common.Service.Impl.BulkEmailService" behaviorConfiguration="BulkEmailService">
<host>
<baseAddresses>
<add baseAddress="http://localhost/TestBulkEmailService/TestBulkEmailService.svc"/>
</baseAddresses>
</host>
<endpoint address="BulkEmailService" binding="basicHttpBinding" contract="TestBulkEmailService.IBulkEmailService" />
<endpoint address="mex" binding="basicHttpBinding" name="mexEndpoint" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="BulkEmailService">
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true" />
<serviceSecurityAudit auditLogLocation="Application"
suppressAuditFailure="true"
serviceAuthorizationAuditLevel="Success"
messageAuthenticationAuditLevel="Success" />
</behavior>
</serviceBehaviors>
</behaviors>
And here is my .svc file which has been hosted in IIS and is running fine when using a client app.
<%# ServiceHost Language="C#" Debug="true" Service="WW.Common.Service.Impl.BulkEmailService" %>
Here's my Implementation and Contract for the WCF Service which I have used as Service reference and have named it as TestBulkEmailService.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using WW.EnterpriseLibrary.Error;
using WW.Common.Service.Contract;
using WW.Common.Data.DTO;
using WW.Common.Data;
using WW.ServiceCore.Error;
using WW.ServiceCore.Log;
using BulkEmailDac = WW.Common.DataAccess.Impl.BulkEmailDac;
namespace WW.Common.Service.Impl
{
public class BulkEmailService : IBulkEmailService
{
private BulkEmailDac emailDac;
ErrorMsg err_msg = new ErrorMsg();
public BulkEmailService()
{
emailDac = new BulkEmailDac();
}
public string Abc(string s1)
{
string result = s1;
return result;
}
/// <summary>
/// Get Bulk Email Record List
/// </summary>
/// <returns></returns>
public BulkEmailDTOList GetBulkEmailInfo(int recordLimit)
{
try
{
return emailDac.GetBulkEmailInfo(recordLimit);
}
catch (Exception ex)
{
if (ex is FaultException<OperationFault>)
{
//throw;
Console.WriteLine("faultException1 Message: " + ex.Message);
throw;
}
else
{
//LOG AND THROW AN UNKNOWN EXCEPTION
ApplicationLog.WriteError(DateTime.Now.ToString() + "|"
+ "GetBulkEmailInfo" + "|"
+ ex.Message + "|"
+ ex.StackTrace);
Console.WriteLine("faultException2 Message: " + ex.StackTrace);
throw new FaultException<OperationFault>(new OperationFault(ex.Message, ErrorMessages.Unknown_Error_Code));
}
}
}
Contract:
using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using WW.EnterpriseLibrary.Error;
using WW.Common.Data.DTO;
namespace WW.Common.Service.Contract
{
[ServiceContract]
public interface IBulkEmailService
{
[OperationContract]
[FaultContractAttribute(typeof(OperationFault))]
BulkEmailDTOList GetBulkEmailInfo(int recordLimit);
[OperationContract]
[FaultContractAttribute(typeof(OperationFault))]
int SendBulkEmail(string emailFm, string emailTo, string ccTo, string subject, string body);
}

Exposing Metadata Exchange for use with svcutil

I am trying to take a very simple (essentially empty/function-less) service I have and generate a proxy with svcutil.exe. Here's my server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.ServiceModel;
class Server2
{
static void Main(string[] args)
{
Console.WriteLine("Server");
Uri baseAddress = new Uri("http://localhost:1234");
var host = new ServiceHost(typeof(TheContractService), baseAddress);
//host.AddServiceEndpoint(typeof(TheContractService), new WSHttpBinding(), "ContractService");
host.Open();
Console.ReadLine();
}
}
[ServiceContract]
class TheContractService
{
[OperationContract]
void Expose()
{
Console.WriteLine("Exposed");
}
}
[DataContract]
class TheContract
{
[DataMember]
public string PublicProperty { get; set; }
[DataMember]
public string PublicField;
[DataMember]
private string PrivateProperty { get; set; }
[DataMember]
private string PrivateField;
[DataMember (Name = "BetterName")]
private string fudshjguhf;
}
Now I just need to set up my .config file to allow MEX -- here is my server config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="ContractService"
behaviorConfiguration="MexServiceBehavior">
<endpoint address="ContractService"
binding="basicHttpBinding"
contract="TheContractService"
/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MexServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
What am I doing wrong here? When I try to run this command:
svcutil /t:code http://localhost:1234/mex /out ContractService.cs /config: ContractService.config
I get either 400 or 405 errors and the client proxy is not generated successfully. Can anyone see any issues with what I currently have? Thanks!
Your class name is TheContractService, but in your config the name attribute of the <service> element is ContractService. Make sure that the value of that attribute is the fully-qualified name (namespace, if any, plus the class name), otherwise the configuration won't be picked up.

Trying to self-host, I get error - wcf service host cannot find any service metadata .. please check if metadata is enabled

I am new to WCF and I've read answers to questions with titles similar to my error but I still cannot see what is wrong.
Following some other tutorials I decided to put my contract and my service in separate projects. Ultimately, I would like to host this in IIS but for now I just wanted to get the WCF Service Host to start (and WCF Test Client).
Here is the app.config in my service project (would this need to be in my contract project too I wonder??...):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="CBMI.TrimWCF.FileService"
behaviorConfiguration="Metadata">
<endpoint address="ws"
binding="wsHttpBinding"
contract="CBMI.TrimWCF.FileServiceContract.IFileService">
</endpoint>
<endpoint name="mex"
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8081/TrimWCFfileService" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Metadata">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Here is the beginning of the FileService.cs file in my services project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.IO;
using System.Diagnostics; // needed for writing to EventLog.
using System.Text; // needed for StringBuilder
using System.ComponentModel;
using System.Web; // need to target .Net Framework 4.0 for the project (for HttpContext)
using TRIMSDK; // for TRIM 6.2. 7.1 (the "COM" SDK)
using CBMI.TrimWCF.Utilities; // separate project for misc classes
using CBMI.TrimWCF.FileServiceContract;
namespace CBMI.TrimWCF.FileService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class FileService : IFileService
{
Database db;
string g_EventSource = "CBMI-TrimBroker";
string g_EventLog = "Application";
public FileService()
{
Finally, here is a bit of my IFileService.cs file in my contracts project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace CBMI.TrimWCF.FileServiceContract
{
[ServiceContract(Name = "IFileService", Namespace = "http://www.cbmiweb.com/TrimWCF/2011/11")]
public interface IFileService
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
[OperationContract]
string DownloadFile(string trimURL
, string TrimRecordNumber
, string CallerPC
, string RequestorID
, out byte[] docContents
, out string returnFiletype
, out string returnFilename);
[OperationContract]
void DownloadFileCF(string trimURL
, string TrimRecordNumber
, string CallerPC = "not specified"
, string RequestorID = "not specified");
[OperationContract]
string SearchCF(string trimURL
, string CFSearchString
, string CallerPC
, string RequestorID);
[OperationContract]
string UploadFileCF(string trimURL
, byte[] incomingArray
, string fileName
, string TrimRecordTypeName
, string metaDataString);
[OperationContract]
string UpdateRecordCF(string trimURL
, string TrimRecordNumber
, string metaDataString);
}
[DataContract(Name = "WCFsample", Namespace = "http://www.cbmiweb.com/TrimWCF/2011/11 ")]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
}
The actual name of your service is BMI.TrimWCF.FileService.FileService (namespace BMI.TrimWCF.FileService, class name FileService). On the name attribute for the <service> tag you have only BMI.TrimWCF.FileService, so WCF can't find the configuration for your service. Please use the fully-qualified name of the service on the configuration, and WCF will then read it correctly.
I will start a service with minimum configuration and then keep adding whatever needed.
as with WCF 4 there default default binding and behavior configured by runtime.
1) service name in your config should be
<service name="BMI.TrimWCF.FileService.FileService">
2) I will change two tags (ServiceMetaData and ServiceDebug) as
3) you need not to include your app.config in your contracts project
4) Refernce your contractProjects in both service project and client project.

405 method not allowed using [webHttpBinding]

I'm getting problems with jquery call wcf. I've already search and found some solutions but it still raise me an error "405 method not allowed". Below is may code
-Interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.ServiceModel;
namespace WcfServiceLibrary
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IContactService" in both code and config file together.
[ServiceContract]
public interface IContactService
{
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
Contact GetContactInfo();
}
}
My service
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.ServiceModel;
namespace WcfServiceLibrary
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ContactService" in both code and config file together.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ContactService : IContactService
{
public Contact GetContactInfo()
{
ContactBL contactBL = new ContactBL();
return contactBL.GetContact();
}
}
}
My object
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime;
using System.Runtime.Serialization;
namespace WcfServiceLibrary
{
[DataContract]
public class Contact
{
[DataMember]
public int Id {get;set;}
[DataMember]
public string Fullname {get; set;}
[DataMember]
public string email { get; set; }
}
}
BL
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WcfServiceLibrary
{
class ContactBL
{
public ContactBL() { }
public Contact GetContact()
{
return new Contact {email="thang.nguyen#saas.com.vn", Fullname="NVTThang",Id=2 };
}
}
}
And also my WCF configuration:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webBinding">
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="myBehavior" name="WcfServiceLibrary.ContactService">
<endpoint address="ajaxEp" behaviorConfiguration="epAjaxBehavior"
binding="webHttpBinding" bindingConfiguration="webBinding" name="epWebHttp"
contract="WcfServiceLibrary.IContactService" />
<endpoint address="mex" binding="mexHttpBinding" name="epMex"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="epAjaxBehavior">
<webHttp />
<enableWebScript/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://localhost"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
The I deploy my wcf on IIS 7.5 then I created a web client using jquery ajax call to my service.
$.ajax({
type: "GET",
url: "http://localhost/WcfTestService/Service.svc/ajaxEp/GetContactInfo",
data: '',
contentType: "application/json;charset=utf-8",
dataType: "json",
processdata: true,
success: function (msg) {
alert(msg);
//ServiceSucceeded(msg);
},
error: ServiceFailed
});
function ServiceFailed(err){
alert(err.responseText);
return;
}
when I call my service it always raises me "405 Method Not Allowed" and I've tried aspnet_regiis -i and ServiceModelReg -i but it didn't effect. Please suggest me any solutions.
Thanks in advance!
I can see a few problems in your service:
For "GET" requests, you should use WebGet, instead of WebInvoke, on your contract:
[ServiceContract]
public interface IContactService
{
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
Contact GetContactInfo();
}
In your endpoint behavior you have 2 behaviors for scripting: webHttp and enableWebScript. You only need the former. The latter is for integration with ASP.NET AJAX specifically.
<endpointBehaviors>
<behavior name="epAjaxBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
This probably isn't causing any issues, but in the $.ajax call, you don't need to specify a content-type, since it's a GET request (so there's no content). Also, since you aren't passing any parameter, you also don't need the data parameter.
$.ajax({
type: "GET",
url: "http://localhost/WcfTestService/Service.svc/ajaxEp/GetContactInfo",
dataType: "json",
success: function (msg) {
alert(msg);
//ServiceSucceeded(msg);
},
error: ServiceFailed
});
Try this in your service:
[ScriptMethod]
public Contact GetContact(...)

WCF endpoint exception

I am just trying with various WCF(in .Net 3.0) scenarios.
I am using self hosting.
I am getting an exception as "Service 'MyServiceLibrary.NameDecorator' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element."
I have a config file as follows (which has an endpoint)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="Lijo.Samples.NameDecorator"
behaviorConfiguration="WeatherServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8010/ServiceModelSamples/FreeServiceWorld"/>
</baseAddresses>
</host>
<endpoint address=""
binding="wsHttpBinding"
contract="Lijo.Samples.IElementaryService" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WeatherServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
And a Host as
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Runtime.Serialization;
namespace MySelfHostConsoleApp
{
class Program
{
static void Main(string[] args)
{
System.ServiceModel.ServiceHost myHost = new ServiceHost(typeof(MyServiceLibrary.NameDecorator));
myHost.Open();
Console.ReadLine();
}
}
}
My Service is as follows
using System.ServiceModel;
using System.Runtime.Serialization;
namespace MyServiceLibrary
{
[ServiceContract(Namespace = "http://Lijo.Samples")]
public interface IElementaryService
{
[OperationContract]
CompanyLogo GetLogo();
}
public class NameDecorator : IElementaryService
{
public CompanyLogo GetLogo()
{
CircleType cirlce = new CircleType();
CompanyLogo logo = new CompanyLogo(cirlce);
return logo;
}
}
[DataContract]
public abstract class IShape
{
public abstract string SelfExplain();
}
[DataContract(Name = "Circle")]
public class CircleType : IShape
{
public override string SelfExplain()
{
return "I am a Circle";
}
}
[DataContract(Name = "Triangle")]
public class TriangleType : IShape
{
public override string SelfExplain()
{
return "I am a Triangle";
}
}
[DataContract]
[KnownType(typeof(CircleType))]
[KnownType(typeof(TriangleType))]
public class CompanyLogo
{
private IShape m_shapeOfLogo;
[DataMember]
public IShape ShapeOfLogo
{
get
{
return m_shapeOfLogo;
}
set
{
m_shapeOfLogo = value;
}
}
public CompanyLogo(IShape shape)
{
m_shapeOfLogo = shape;
}
}
}
Could you please help me to understand what I am missing here?
Thanks
Lijo
You're self-hosting in a console app - how is your config set up??
Does your MySelfHostConsoleApp project have an app.config file?
Do you have the MySelfHostConsoleApp.exe.config in the same directory as the MySelfHostConsoleApp.exe file?
The error message just really means the config cannot be found and thus cannot be interpreted and used.
UPDATE: the other option is that WCF cannot interpret the config if it's present.
Check this out:
in your .NET code, your service class that implements the service is called MyServiceLibrary.NameDecorator
however, in your config, you call your service:
<service name="Lijo.Samples.NameDecorator"
That's not going to work! You're mixing up the .NET namespaces and the service namespaces here - and the name you need to put in your service-side config is the .NET fully qualified type name (including the .NET namespace - not the service namespace!).
Your service host will look for an entry <service name="MyServiceLibrary.NameDecorator"> based on your code - but it won't find it.
So you need to make sure to sync those two things up - the fully qualified service class name (including namespace and all) MUST match the name="...." attribute in your <service> tag in your config.