Silverlight and Duplex WCF Service - c#

I have added a WCF service reference to Silverlight application and here's what the binding from web.config that I have looks like
<bindings>
<wsDualHttpBinding>
<binding name="wsDualHttpBinding">
<security mode="None" />
</binding>
</wsDualHttpBinding>
<pollingDuplexHttpBinding>
<binding name="multipleMessagesPerPollPollingDuplexHttpBinding"
duplexMode="MultipleMessagesPerPoll" />
</pollingDuplexHttpBinding>
</bindings>
And I have this snippet to create a service client instance
var serviceClient = new DuplexCallerIdServiceClient(
new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll),
new EndpointAddress("http://localhost:51445/Service/MyService.svc"));
My concern is that why do I have to provide an absolute url in code. I have a winforms application that uses the same service and I can just do new DuplexCallerIdServiceClient() to create a service client instance which seems ideal. Is there any way I can work around it. I cannot change the binding settings.
Thanks

You do not have to hardcode the service URL. Replace the hard coded string that either is passed in as an argument or makes a function call (or gets some object's property) to populate the constructor with a valid service URL.
Here's one way among many:
var serviceClient = new DuplexCallerIdServiceClient(
new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll),
new EndpointAddress(Info.Instance.ServiceURL));
Where Info is a singleton object, Instance gets the singleton's instance and ServiceUrl is a string property that comes from... wherever. Database, config file, hard coded to start etc...
P.S. Careful with the Singleton pattern, but as config info entities they can be very useful.

Related

dynamically set the base address of a WCF service in the client

I built a WCF service library and hosted it through a host application. Then I constructed a client application, but it seems that the address of the service host is hard coded in the client program. What if the host changes its address? Is it possible to write the client application so that the address of the host can be entered by the client at run time?
Yes, it's possible, if you write the WCF client proxy by hand, instead of generating it automatically with Visual Studio adding a service reference.
Let's start from this example (https://learn.microsoft.com/it-it/dotnet/framework/wcf/feature-details/how-to-use-the-channelfactory), just to understand how ChannelFactory works, and then modify it a little bit, adding the following function.
private ChannelFactory<IMath> _myChannelFactory;
// ...
private IMath GetChannel(string endpointConfigurationName, string endpointAddress)
{
if (_myChannelFactory == null)
{
this.DebugLog("Channel factory is null, creating new one");
if (String.IsNullOrEmpty(endpointAddress))
{
_myChannelFactory = new ChannelFactory<IMath>(endpointConfigurationName);
}
else
{
_myChannelFactory = new ChannelFactory<IMath>(endpointConfigurationName, new EndpointAddress(endpointAddress));
}
}
return _myChannelFactory.CreateChannel();
}
You can define the default server IP in the client App.config file
<system.serviceModel>
<!-- ... -->
<client>
<endpoint address="net.tcp://192.168.10.55:81/math/" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IMath"
contract="MyNamespace.IMath" name="NetTcpBinding_IMath" />
</client>
</system.serviceModel>
In this way, when GetChannel("NetTcpBinding_IMath", "net.tcp://127.0.0.1:81/math") is called, it picks up the endpoint configuration from App.config file, replacing the default address (192.168.10.55) with the new one (127.0.0.1).
Some more documentation about ChannelFactory: https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channelfactory-1.createchannel?view=netframework-4.8

Inject Service Reference into .NET with AppSettings.json and Startup.cs

My project is not finding the service reference endpoint in runtime. I believe it's due to incorrect injection in my Startup.cs. I'm new to the appsettings.json and Startup.cs method of configuration but have successfully scoped my class library and Dbcontext in the Startup.cs.
Note, if it makes a difference, this VS solution contains a class library and a .NET/angular2 web project. The call to the Service is initiated from angular website to the Web API, which calls methods on the class library where actual processing occurs.
The service reference "CybersourceTrxnProcessor" shows up in my class library project (see image) and ITransactionProcessor is exposed and accessible (i.e. code-hinting working perfectly). The web project DOES NOT have the service reference in the solution explorer.
When I added the reference, the sections were added to the app.config file (see below) and I copied them to the web.config in the web project.
How do I 'recreate' the web.config settings in the appsettings and Startup?
When attempting to process a test payment, this line of code throws an exception:
TransactionProcessorClient proc = new TransactionProcessorClient("ITransactionProcessor");
I have also tried defining the endpoint manually just prior but the same error results:
System.ServiceModel.EndpointAddress theendpoint = new System.ServiceModel.EndpointAddress("https://ics2wstesta.ic3.com/commerce/1.x/transactionProcessor");
TransactionProcessorClient proc = new TransactionProcessorClient("ITransactionProcessor", theendpoint);
This is the error:
An Exception occurred while trying to process your payment. Please try again. Could not find endpoint element with name 'ITransactionProcessor' and contract 'CybersourceTrxnProcessor.ITransactionProcessor' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element.
Here is what config file looks like, generated when I added the service reference to the project in Visual Studio (and also matches what's in an older MVC project):
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ITransactionProcessor">
<security mode="TransportWithMessageCredential" />
</binding>
<binding name="ITransactionProcessor1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://ics2wstesta.ic3.com/commerce/1.x/transactionProcessor" binding="basicHttpBinding" bindingConfiguration="ITransactionProcessor"
contract="CybersourceTrxnProcessor.ITransactionProcessor" name="portXML" />
</client>
</system.serviceModel>
This is the appsettings.json:
"ITransactionProcessor": {
"security": { "mode": "TransportWithMessageCredential" },
"client": {
"endpoint": {
"address": "https://ics2wstesta.ic3.com/commerce/1.x/transactionProcessor",
"binding": "basicHttpBinding",
"bindingConfiguration": "ITransactionProcessor",
"contract": "CybersourceTrxnProcessor.ITransactionProcessor",
"name": "portXML"
}
}
}
This is what I have in Startup.cs (also need to set the Security mode to TransportWithMessageCredential as prescribed by Cybersource docs):
services.AddScoped<ITransactionProcessor>(provider => {
var client = new TransactionProcessorClient();
client.Endpoint.Address = new EndpointAddress(Configuration["ITransactionProcessor:client:endpoint:address"]);
client.Endpoint.Contract = new System.ServiceModel.Description.ContractDescription(Configuration["ITransactionProcessor:client:endpoint:contract"]);
client.Endpoint.Binding = new System.ServiceModel.BasicHttpBinding();
client.Endpoint.Name = "portXML";
return client;
});
Just FYI, I finally figured this out. Everything I had was correct except ONE tiny thing (doesn't it almost always come down to something simple). The error actually told me exactly what it needed. I simply needed to change my appsettings.json like so:
"name": "portXML"
to
"name": "ITransactionProcessor"

WCF 4.0 SOA Commit as Transcation

In WCF 4.0, How can I commit 3 different service operation as a single Transaction? (Commit in SOA)
I have 3 different WCF service like below, Each service method invokes DB operation
service1.CreateEmployee();
service2.SendSetupRequestForEmployee();
service3.GiveOfficePermissionToEmployee();
Even if one operation fails entire thing should be rolled back...any help appreciated.
The short answer: Make your service calls under a TransactionScope, and make sure the calls themselves are set up to run under transactions.
TLDR read this article here.
Basically, you need to decorate your Operation Contract method as such:
[TransactionFlow(TransactionFlowOption.Allowed)]
void MyWcfServiceCall() {...}
and the service method call itself with:
[OperationBehavior(TransactionScopeRequired = true)]
void MyWcfServiceCall() {...}
and call under a TransactionScope
using (TransactionScope tx = new TransactionScope(TransactionScopeOption.RequiresNew)) {
myServiceClient.MyWcfServiceCall();
myOtherServiceClient.MyOtherWcfServiceCall();
tx.Complete();
}
in your config file for the bindings, set transactionFlow to true:
<bindings>
<wsHttpBinding>
<binding name="MyServiceBinding" transactionFlow="true" ... />
</wsHttpBinding>
</bindings>

how to access HttpContext.Current.Application

Hello i have problem accessing HttpContext.Current.Application From global.asax its seems to be null every time i try to access it.
How can i to this?
HttpContext.Current.Application.Lock();
HttpContext.Current.Application["Actions"] = "hello";
HttpContext.Current.Application.UnLock();
Thanks
In Global.asax, you're not in an actual request, so there's no current request nor context you can go by. However, the Global class is a subclass of HttpApplication, so just use 'this', like:
this["Actions"]
From MSDN
To get the HttpApplication object for the current HTTP request, use ApplicationInstance. (ASP.NET uses ApplicationInstance instead of Application as a property name to refer to the current HttpApplication instance in order to avoid confusion between ASP.NET and classic ASP. In classic ASP, Application refers to the global application state dictionary.)
You need to turn on access to the Application instance object in your web.config file like so:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Be sure to include a reference to System.Web.

RIA services WCF timeout

I have an application which is written in silverlight 3.0. It uses RIA services to communicate between the client and server.
My question doesn't seem to be answered very well on the web. The client communicates to the server using RIA services, which uses WCF behind the scenes. If the communication takes more than 60 seconds it times out with this message,
'Load operation failed for query 'ApplyUpgrade'. The HTTP requrest to 'http://localhost:52403/ClientBin/DatabaseUpgradeTool-Web-UpgradePackageDomainService.svc/binary' has exceeded the allotted timeout. The time allotted to this operation may have been a portion of a longer timeout.'
My server is performing a database upgrade, so it is valid for it to take more than 60 seconds. Probably double or triple that.
I tried settings like this in the web.config,
<services>
<service name="DatabaseUpgradeTool.Web.UpgradePackageDomainService">
<endpoint address="" binding="wsHttpBinding" contract="DatabaseUpgradeTool.Web.UpgradePackageDomainService"></endpoint>
<endpoint address="/soap" binding="basicHttpBinding" contract="DatabaseUpgradeTool.Web.UpgradePackageDomainService"></endpoint>
<endpoint address="/binary" binding="customBinding" bindingConfiguration="BinaryHttpBinding" contract="DatabaseUpgradeTool.Web.UpgradePackageDomainService"></endpoint>
</service>
</services>
<bindings>
<customBinding>
<binding name="BinaryHttpBinding"
receiveTimeout="00:00:10"
sendTimeout="00:00:10"
openTimeout="00:00:10"
closeTimeout="00:00:10">
<binaryMessageEncoding />
<httpTransport keepAliveEnabled="true"/>
</binding>
</customBinding>
</bindings>
Still no joy. Any ideas as to what is wrong with what I have tried above? I would expect the above to cause it to timeout within 10 seconds, not 60.
Thanks.
Not sure if this will help, I haven't tried it with time outs configurations, but it might point you in the right direction:
http://blogs.objectsharp.com/CS/blogs/dan/archive/2010/04/13/maxitemsinobjectgraph-wcf-ria-services-exception.aspx
I faced the same problem, I posted the answer to this question here: Silverlight 4 WCF RIA Service Timeout Problem
Here is the answer:
I'll explain my context and I wish it will work for my. I'm sure about that.
First of all to call RIA services, and using some domain context, in my example:
EmployeeDomainContext context = new EmployeeDomainContext();
InvokeOperation<bool> invokeOperation = context.GenerateTMEAccessByEmployee(1, 'Bob');
invokeOperation.Completed += (s, x) =>
{....};
Nothing new until here. And with this I was facing every time that same timeout exception after 1 minute. I spend quite a lot of time trying to face how to change the timeout definition, I tried all possible changes in Web.config and nothing. The solution was:
Create a CustomEmployeeDomainContext, that is a partial class localizated in the same path of the generated code and this class use the hook method OnCreate to change the behavior of created domain context. In this class you should wrote:
public partial class EmployeeDomainContext : DomainContext
{
partial void OnCreated()
{
PropertyInfo channelFactoryProperty = this.DomainClient.GetType().GetProperty("ChannelFactory");
if (channelFactoryProperty == null)
{
throw new InvalidOperationException(
"There is no 'ChannelFactory' property on the DomainClient.");
}
ChannelFactory factory = (ChannelFactory)channelFactoryProperty.GetValue(this.DomainClient, null);
factory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 10, 0);
}
}
I looking forward for you feedback.

Categories