.NET Framework Bookmark and Share   
 index > .NET StockTrader Sample Application > Calling one service from another hosted service.
 

Calling one service from another hosted service.

Hi Greg,

I am stuck in a weird problem. I have hosted some services in configuration Service as below.

Now, I am trying to invoke the "Security Service netTcp" from a web client. It is working fine.
In the client repository, I successfully added the remote services and connections to hostfor each service using the "configweb".
The problem arises when I try to call one hosted service from another hosted service. The scenario is as below -
Web Client --> "ClientSetup Client Service netTcp" which in turn has to invoke "Security Service netTcp". When the code tries toinstantiate the Loadbalancingclient for "Security Service netTcp", it gives error- the friendly name is invalid and could not be found.
Is there something additional I have to do to call a hosted service from within a hosted service.
Thanks,
Priyaroop Singh
Priyaroop Singh

Yes. First, on Monday the new StockTrader and Configuration Service 2.02 code will be posted on MSDN (not sure what time--it has been sent for release though).

If it is your host that is trying to call a service (not the Web client) that it itself hosts...two things:

1) Typically in such a scenario you can call the service directly without going over WCF...just instantiate the implementation class directly! This is the most performant way for a single host hosting a service to directly invoke the service operations it is hosting--without going through any serialization/deserialzation or WCF network operations. This might not be ideal if your service operations depend on WCF operation contexts or expects there to be a service operation context, however. In which case you *can* of course have a host invoke a service operation via WCF (A client to itself) to a service the same program is hosting.

2) To have a service host invoke it's own services (client to itself) over WCF using Config Service (with load balancing and using Config Service generated client), you will need to establish a Connected Service defintion for the host itself via ConfigWeb, to the appropriate endpoint(s) you want to invoke, and pass in the contract type in the host's initialization logic just like you did for the 'pure' web client. This establishes the service friendly name in the host's repository as a connected service (otherwise it is just listed as a 'hosted service'). You will also then use add connection tab also just as you did for the pure web client.

3) #2 above works with the new release going up Monday (2.02)....there is a bug that makes this not work with the existing 2.01 release.

-Greg

Gregory Leake

I just tested this scenario again, and do not get any errors. This is a bit of a strange error, as a call on a missing method, unless invoked by reflection, would give a compile error, not a runtime error. Make sure you have re-built using the 2.02 shared libraries, and all the libraries that begin with ConfigService.[assemblyname].dll in your .exe's folder are the correct, new version. To test this scenario (A host calling one of its own services/endpoints via WCF), I used the SimpleTestHarness solution, in \Configuration\SimpleTestHarness. This is what I did:

1) Ensured the updated client generated by the Repository Creation tool works in the SimpleTestClient solution. To do this, I used the Repository Create tool to re-generate the client class, pointing to \Builds\SimpleTestHost\Sample.SimpleServiceContract.dll as the contract assembly. I used the following options based on the existing TestClient.sln solution:

Namespace for client class: Sample.SimpleServiceClient

Class name: SimpleServiceClient

Settings class namespace: Sample.SimpleTestClientConfigurationSettings

2) This generates a new file, SimpleServiceClient.cs. I then opened the \Configuration\SimpleTestHarness\TestClient.sln in Visual Studio. In the project I deleted the existing SimpleTestClient.cs file, and then added the Repository-tool generated client from step 1 above SimpleServiceClient.cs. A then rebuilt the entire solution after doing a "clean" on it to ensure I was getting all new assemblies built.

3) I then logged into the Simple Client's Config Service (which is IIS-hosted) using ConfigWeb, with login address http://localhost:80/simpleweb/config.svc(localadmin userid, password 'yyy').

4) I next launched the existing SimpleTestHost Windows self-host program from the StockTrader-->Configuration-->Samples program group in the start menu. After launching the service host, I used ConfigWeb to add a Connection to server 'localhost' for the service Simple Service wsHttp (the only endpoint the host exposes). I then used the browser to goto http://localhost/simpleweb , and tested the service call, which is now using the newly generated client class. This worked.

5) Next, to get to your scenario, I closed the Simple Test Host Windows host, and opened its solution, \Configuration\SimpleTestHarness\TestHost.sln. I added a new project to this solution, named it Sample.SimpleTestClient2. I then added the same SimpleServiceClient.cs file generated in step one, but made the following changes to adjust a couple of things for this new project--namely the namespace changed to Sample.SimpleTestClient2, and the "using Sample.SimpleTestClientConfigurationSettings" changed to "using Sample.SimpleServiceConfigurationSettings". I added appropriate references to the ConfigService shared libraries, and recompiled to make sure the new client project compiled ok in the new project.

6) Now that I have a client project living in the Host Solution, capable of being a client to its own hosted service (ISimpleService), I need to do two things:

a) Adjust the initialization logic of the Simple Service windows host to include the contract ISimpleService as a connected service contract. This is done in the SimpleTestHostWindowsConsole project, in the program.cs file. The following is the new Application.Run line, with the change highlighted:

//This starts the Windows program main form, which is a class that inherits from a base class with all the Windows logic/display layout pre-provided.

Application.Run(new SimpleServiceHostConsole(new Settings(), new ConfigurationService(), new NodeCommunication(), null, new ConfigurationActions(), startupList, null, new object[] {typeof(ISimpleService) }, "Sample.SimpleTestHostWindowsConsole.SimpleServiceBanner.bmp"));

b) Add logic to actually test the host invoking its own service. To do this, I changed the implementation logic for the SayHello method in the SimpleServiceImplementation project....the new logic looks at follows:

public string SayHello(string message)

{

ConfigUtility.writeConsoleMessage("Received message: " + message + ". Responding!\n", EventLogEntryType.Information, false, new Settings());

SimpleServiceClient myClient = new SimpleServiceClient("Simple Service wsHttp");

if (!message.Equals("Host to Host"))

{

string hostmessage = myClient.SayHello("Host to Host");

ConfigUtility.writeConsoleMessage("\nHost to Host return is: " + hostmessage, EventLogEntryType.Information, false, new Settings());

}

return message + " -- Simple Service Says 'Hello Back to You', whoever you are!";

}

7) Next, I need to add, via ConfigWeb, a Connected Service defintion for the host, to it's own service (ISimpleService). I used ConfigWeb to login to http://localhost:7002/Simple/Config(with the Windows Self host program running). Using the Remote Svcs tab in ConfigWeb, I added a new Connected Service (there are none starting out)...by pointing to the http://localhost:7002/SimpleConfig and clicking "Get Services!" button. I already have a proper client defintion and appropriate binding, which are selected automatically, so I just can click Add.

8) Next, I use the Connection tab in ConfigWeb to add an initial connection to the host program (itself), simply using localhost as the server name.

9) Now, I goback to http://localhost/simpleweb/default.aspx, and invoke the service. At this point, the client app will invoke SayHello, which in turn, one time, will then instantiate a client to itself and invoke itself (as a test) via WCF and ConfigService infrastructure. This works for me. Note, per earlier message, the better/faster/easier way for a service host to invoke one of its own service methods(vs a remote call to a remote host), is simply to instatiate the class directly, and not go over WCF at all. the code would look as follows (and would not require the Host program to even have a Connected Service Defintion to itself):

public string SayHello(string message)

{

ConfigUtility.writeConsoleMessage("Received message: " + message + ". Responding!\n", EventLogEntryType.Information, false, new Settings());

if (!message.Equals("Host to Host"))

{

SimpleService myPrivateSimpleService = new SimpleService();

string hostmessage = myPrivateSimpleService .SayHello("Host to Host");

ConfigUtility.writeConsoleMessage("\nHost to Host return is: " + hostmessage, EventLogEntryType.Information, false, new Settings());

}

return message + " -- Simple Service Says 'Hello Back to You', whoever you are!";

}

Gregory Leake

Yes. First, on Monday the new StockTrader and Configuration Service 2.02 code will be posted on MSDN (not sure what time--it has been sent for release though).

If it is your host that is trying to call a service (not the Web client) that it itself hosts...two things:

1) Typically in such a scenario you can call the service directly without going over WCF...just instantiate the implementation class directly! This is the most performant way for a single host hosting a service to directly invoke the service operations it is hosting--without going through any serialization/deserialzation or WCF network operations. This might not be ideal if your service operations depend on WCF operation contexts or expects there to be a service operation context, however. In which case you *can* of course have a host invoke a service operation via WCF (A client to itself) to a service the same program is hosting.

2) To have a service host invoke it's own services (client to itself) over WCF using Config Service (with load balancing and using Config Service generated client), you will need to establish a Connected Service defintion for the host itself via ConfigWeb, to the appropriate endpoint(s) you want to invoke, and pass in the contract type in the host's initialization logic just like you did for the 'pure' web client. This establishes the service friendly name in the host's repository as a connected service (otherwise it is just listed as a 'hosted service'). You will also then use add connection tab also just as you did for the pure web client.

3) #2 above works with the new release going up Monday (2.02)....there is a bug that makes this not work with the existing 2.01 release.

-Greg

Gregory Leake

Hi Greg,

I have upgraded to 2.02 release and am still facing problems whenthe Service host tries to invoke its own service.

I have successfully established the service friendly names in the host repository as a connected service.

The moment I try to instantiate the client class passing the service friendly name it gives me error -

Method not found: 'Void VersionSvcClient..ctor(System.String)'.

I am invoking this from a windows application. The same thing works fine when I invoke the service from a web application.

Thanks,

Priyaroop

Priyaroop Singh

I just tested this scenario again, and do not get any errors. This is a bit of a strange error, as a call on a missing method, unless invoked by reflection, would give a compile error, not a runtime error. Make sure you have re-built using the 2.02 shared libraries, and all the libraries that begin with ConfigService.[assemblyname].dll in your .exe's folder are the correct, new version. To test this scenario (A host calling one of its own services/endpoints via WCF), I used the SimpleTestHarness solution, in \Configuration\SimpleTestHarness. This is what I did:

1) Ensured the updated client generated by the Repository Creation tool works in the SimpleTestClient solution. To do this, I used the Repository Create tool to re-generate the client class, pointing to \Builds\SimpleTestHost\Sample.SimpleServiceContract.dll as the contract assembly. I used the following options based on the existing TestClient.sln solution:

Namespace for client class: Sample.SimpleServiceClient

Class name: SimpleServiceClient

Settings class namespace: Sample.SimpleTestClientConfigurationSettings

2) This generates a new file, SimpleServiceClient.cs. I then opened the \Configuration\SimpleTestHarness\TestClient.sln in Visual Studio. In the project I deleted the existing SimpleTestClient.cs file, and then added the Repository-tool generated client from step 1 above SimpleServiceClient.cs. A then rebuilt the entire solution after doing a "clean" on it to ensure I was getting all new assemblies built.

3) I then logged into the Simple Client's Config Service (which is IIS-hosted) using ConfigWeb, with login address http://localhost:80/simpleweb/config.svc(localadmin userid, password 'yyy').

4) I next launched the existing SimpleTestHost Windows self-host program from the StockTrader-->Configuration-->Samples program group in the start menu. After launching the service host, I used ConfigWeb to add a Connection to server 'localhost' for the service Simple Service wsHttp (the only endpoint the host exposes). I then used the browser to goto http://localhost/simpleweb , and tested the service call, which is now using the newly generated client class. This worked.

5) Next, to get to your scenario, I closed the Simple Test Host Windows host, and opened its solution, \Configuration\SimpleTestHarness\TestHost.sln. I added a new project to this solution, named it Sample.SimpleTestClient2. I then added the same SimpleServiceClient.cs file generated in step one, but made the following changes to adjust a couple of things for this new project--namely the namespace changed to Sample.SimpleTestClient2, and the "using Sample.SimpleTestClientConfigurationSettings" changed to "using Sample.SimpleServiceConfigurationSettings". I added appropriate references to the ConfigService shared libraries, and recompiled to make sure the new client project compiled ok in the new project.

6) Now that I have a client project living in the Host Solution, capable of being a client to its own hosted service (ISimpleService), I need to do two things:

a) Adjust the initialization logic of the Simple Service windows host to include the contract ISimpleService as a connected service contract. This is done in the SimpleTestHostWindowsConsole project, in the program.cs file. The following is the new Application.Run line, with the change highlighted:

//This starts the Windows program main form, which is a class that inherits from a base class with all the Windows logic/display layout pre-provided.

Application.Run(new SimpleServiceHostConsole(new Settings(), new ConfigurationService(), new NodeCommunication(), null, new ConfigurationActions(), startupList, null, new object[] {typeof(ISimpleService) }, "Sample.SimpleTestHostWindowsConsole.SimpleServiceBanner.bmp"));

b) Add logic to actually test the host invoking its own service. To do this, I changed the implementation logic for the SayHello method in the SimpleServiceImplementation project....the new logic looks at follows:

public string SayHello(string message)

{

ConfigUtility.writeConsoleMessage("Received message: " + message + ". Responding!\n", EventLogEntryType.Information, false, new Settings());

SimpleServiceClient myClient = new SimpleServiceClient("Simple Service wsHttp");

if (!message.Equals("Host to Host"))

{

string hostmessage = myClient.SayHello("Host to Host");

ConfigUtility.writeConsoleMessage("\nHost to Host return is: " + hostmessage, EventLogEntryType.Information, false, new Settings());

}

return message + " -- Simple Service Says 'Hello Back to You', whoever you are!";

}

7) Next, I need to add, via ConfigWeb, a Connected Service defintion for the host, to it's own service (ISimpleService). I used ConfigWeb to login to http://localhost:7002/Simple/Config(with the Windows Self host program running). Using the Remote Svcs tab in ConfigWeb, I added a new Connected Service (there are none starting out)...by pointing to the http://localhost:7002/SimpleConfig and clicking "Get Services!" button. I already have a proper client defintion and appropriate binding, which are selected automatically, so I just can click Add.

8) Next, I use the Connection tab in ConfigWeb to add an initial connection to the host program (itself), simply using localhost as the server name.

9) Now, I goback to http://localhost/simpleweb/default.aspx, and invoke the service. At this point, the client app will invoke SayHello, which in turn, one time, will then instantiate a client to itself and invoke itself (as a test) via WCF and ConfigService infrastructure. This works for me. Note, per earlier message, the better/faster/easier way for a service host to invoke one of its own service methods(vs a remote call to a remote host), is simply to instatiate the class directly, and not go over WCF at all. the code would look as follows (and would not require the Host program to even have a Connected Service Defintion to itself):

public string SayHello(string message)

{

ConfigUtility.writeConsoleMessage("Received message: " + message + ". Responding!\n", EventLogEntryType.Information, false, new Settings());

if (!message.Equals("Host to Host"))

{

SimpleService myPrivateSimpleService = new SimpleService();

string hostmessage = myPrivateSimpleService .SayHello("Host to Host");

ConfigUtility.writeConsoleMessage("\nHost to Host return is: " + hostmessage, EventLogEntryType.Information, false, new Settings());

}

return message + " -- Simple Service Says 'Hello Back to You', whoever you are!";

}

Gregory Leake

Hi Greg,

Thanks a lot for your help. This is exactly what I have been trying to achieve. The only difference I see between the two is that I am using netTcp binding instead of wsHttp. I don't think that should be a concern.

I will try to do a fresh install (new repository and all)and see if it works.

Also, I noticed another small problem. In the service contract, if I say "SessionMode = WCF::SessionMode.Allowed"; the service works fine. The moment I give "SessionMode = WCF::SessionMode.Required", the thing stops working and the method calls just start to time out. When I debug the code, the control goes till the method call. After that it waits for a minute (or whatever is the timeout in config settings), and then throws a timeout exception. I didn't debug the Config Service code. I'll try to debug it to see if it is getting into some endless loop.

Once again, thanks a lot. Really do appreciate that.

Priyaroop Singh
Priyaroop Singh

Hi Greg,

This is working fine now. I am able to successfully invoke a service from another service (both serivces hosted on the same Config host). The issue was in the Client Settings class. I had given incorrect client settings class while generating theservice clientfor my second service.

Thanks,

Priyaroop Singh

Priyaroop Singh

You can use google to search for other answers

Custom Search

More Threads

• The Test Connection Failed
• changes in dataset does not update database
• Detailed Performance Report Available?
• Instantiating TradeService at Every Call
• Createneweventsource missing
• Configuration Service 2.02 and StockTrader 2.02 have been sent to MSDN---expect to appear on StockTrader site sometime Monday
• Population of initial Settings values
• Existing connection was forcibly closed by the remote host while other service work
• Node Active Service ID Not Passing Validation On Startup
• .Net benchmark application without DB