WCF woes: request and response classes - c#

Could someone please explain to me how the request and response model works in WCF? I have a simple service that exposes a method called getRateOfExchange with a single integer parameter that returns rateOfExchange[], but the Reference.cs file that is generated from the service contains lots of classes:
getRateOfExchange (seems to be the parameters)
getRateOfExchangeRequest
getRateOfExchangeResponse
I have tried every permutation of these classes and their methods but nothing works. Intuitively you would expect to create a request object with the parameter object as a parameter, and then pass this request to the method on the response that executes the request to the sever.
But no.
It has to be painful.
Can someone please explain?
UPDATE
Thank you Gigi, but my classes don't look like that.
If I follow your model, my request would look like this:
CharterServices.charterServiceClient proxy = new CharterServices.charterServiceClient();
using (OperationContextScope scope = new OperationContextScope(proxy.InnerChannel));
{
using (proxy as IDisposable)
{
var response = proxy.getRateOfExchange()
}
}
However, my getRateOfExchange() method requires a getRateOfExchange object, so the above code doesn't compile.The getRateOfExchange class contains parameters that are the parameters to the proxy.getRateOfExchange() method. I have tried creating an instance of this class and passing it the above method, like this:
using (proxy as IDisposable)
{
var rateOfExchange = new Service.getRateOfExchange()
{
charterEnquiryId = 1550003668
};
using (OperationContextScope scope = new OperationContextScope(proxy.InnerChannel));
{
using (proxy as IDisposable)
{
var response = proxy.getRateOfExchange(rateOfExchange);
foreach (var rateOfExcchange in response)
{
Debug.WriteLine(rateOfExcchange.fromCurrencyName);
}
}
}
}
but it hangs when trying to call getRateOfExchange().
Aaargh! I know the service is working because I can execute a request in SoapUI to the same WSDL.
Can you help?

It's actually not painful at all. Once you generate the proxy/client classes, you just create an instance of the client and then call the methods as if they were local method calls.
I can't explain the whole process here, but I'll instead refer you to the intro I wrote over a year ago which explains the whole process in terms of a simple example.
You can test the service using the WCF Test Client even before you've written your own client. Writing the client is very easy if you use the Service References.
Here's an excerpt from the code from that blog post illustrating how to use client code, modified to have a using block and use the var keyword for brevity:
static void Main(string[] args)
{
using (var service = new ServiceReference1.Service1Client())
{
var response = service.GetData(5);
Console.WriteLine(response);
Console.ReadLine();
}
}

The system was throwing an exception which was not being caught, so the component model decided to hang! Fixed it now.

Suppose rateOfExchange is a List of integers, I have just added 10 numbers to it, from 1 to 10.
Then this list is sent as a parameter to the getRateOfExchange method of the service client object.
List<int> rateOfExchange=new List<int>();
for(int i=0;i<10;i++)
{
rateOfExchange.Add(i);
}
//Service Call
ServiceClient obj=new ServiceClient();
var response=obj.getRateOfExchange(rateOfExchange);
foreach(var item in response)
{
Console.WriteLine(item);
}
Console.ReadLine();
Hope it helps.

Related

Applying custom request options for a remote SPARQL connector in dotNetRdf

I'm trying to add custom headers to the HTTP requsets a SPARQL endpoint connector issues. The connector can use a custom remote endpoint, which inherits an ApplyCustomRequestOptions method I can override. Documentation for that method says
[...] add any additional custom request options/headers to the request.
However my overridden method is never called (so my custom options are not applied, so I can't add the headers).
The following code works as expected, except that my ApplyCustomRequestOptions is never invoked:
using System;
using System.Net;
using VDS.RDF.Query;
using VDS.RDF.Storage;
class Program
{
static void Main(string[] args)
{
var endpointUri = new Uri("https://query.wikidata.org/sparql");
var endpoint = new CustomEndpoint(endpointUri);
using (var connector = new SparqlConnector(endpoint))
{
var result = connector.Query("SELECT * WHERE {?s ?p ?o} LIMIT 1");
}
}
}
public class CustomEndpoint : SparqlRemoteEndpoint
{
public CustomEndpoint(Uri endpointUri) : base(endpointUri) { }
protected override void ApplyCustomRequestOptions(HttpWebRequest httpRequest)
{
// This is never executed.
base.ApplyCustomRequestOptions(httpRequest);
// Implementation omitted.
}
}
Is this the correct way to use these methods? If it isn't, what is it?
BTW this is dotNetRdf 1.0.12, .NET 4.6.1. I've tried multiple SPARQL endpoints, multiple queries (SELECT & CONSTRUCT) and multiple invocations of SparqlConnector.Query.
This is a bug. I've found the problem and fixed it and submitted a PR. You can track the status of the issue here: https://github.com/dotnetrdf/dotnetrdf/issues/103

SignalR server --> client call not working

I'm currently using SignalR to communicate between a server and multiple separate processes spawned by the server itself.
Both Server & Client are coded in C#. I'm using SignalR 2.2.0.0
On the server side, I use OWIN to run the server.
I am also using LightInject as an IoC container.
Here is my code:
public class AgentManagementStartup
{
public void ConfigurationOwin(IAppBuilder app, IAgentManagerDataStore dataStore)
{
var serializer = new JsonSerializer
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
TypeNameHandling = TypeNameHandling.Auto,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
};
var container = new ServiceContainer();
container.RegisterInstance(dataStore);
container.RegisterInstance(serializer);
container.Register<EventHub>();
container.Register<ManagementHub>();
var config = container.EnableSignalR();
app.MapSignalR("", config);
}
}
On the client side, I register this way:
public async Task Connect()
{
try
{
m_hubConnection = new HubConnection(m_serverUrl, false);
m_hubConnection.Closed += OnConnectionClosed;
m_hubConnection.TraceLevel = TraceLevels.All;
m_hubConnection.TraceWriter = Console.Out;
var serializer = m_hubConnection.JsonSerializer;
serializer.TypeNameHandling = TypeNameHandling.Auto;
serializer.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
m_managementHubProxy = m_hubConnection.CreateHubProxy(AgentConstants.ManagementHub.Name);
m_managementHubProxy.On("closeRequested", CloseRequestedCallback);
await m_hubConnection.Start();
}
catch (Exception e)
{
m_logger.Error("Exception encountered in Connect method", e);
}
}
On the server side I send a close request the following way:
var managementHub = GlobalHost.ConnectionManager.GetHubContext<ManagementHub>();
managementHub.Clients.All.closeRequested();
I never receive any callback in CloseRequestedCallback. Neither on the Client side nor on the server side I get any errors in the logs.
What did I do wrong here ?
EDIT 09/10/15
After some research and modifications, I found out it was linked with the replacement of the IoC container. When I removed everything linked to LightInject and used SignalR as is, everything worked. I was surprised about this since LightInject documented their integration with SignalR.
After I found this, I realised that the GlobalHost.DependencyResolver was not the same as the one I was supplying to the HubConfiguration. Once I added
GlobalHost.DependencyResolver = config.Resolver;
before
app.MapSignalR("", config);
I am now receiving callbacks within CloseRequestedCallback. Unfortunately, I get the following error as soon as I call a method from the Client to the Server:
Microsoft.AspNet.SignalR.Client.Infrastructure.SlowCallbackException
Possible deadlock detected. A callback registered with "HubProxy.On"
or "Connection.Received" has been executing for at least 10 seconds.
I am not sure about the fix I found and what impact it could have on the system. Is it OK to replace the GlobalHost.DependencyResolver with my own without registering all of its default content ?
EDIT 2 09/10/15
According to this, changing the GlobalHost.DependencyResolver is the right thing to do. Still left with no explanation for the SlowCallbackException since I do nothing in all my callbacks (yet).
Issue 1: IoC Container + Dependency Injection
If you want to change the IoC for you HubConfiguration, you also need to change the one from the GlobalHost so that returns the same hub when requesting it ouside of context.
Issue 2: Unexpected SlowCallbackException
This exception was caused by the fact that I was using SignalR within a Console Application. The entry point of the app cannot be an async method so to be able to call my initial configuration asynchronously I did as follow:
private static int Main()
{
var t = InitAsync();
t.Wait();
return t.Result;
}
Unfortunately for me, this causes a lot of issues as described here & more in details here.
By starting my InitAsync as follow:
private static int Main()
{
Task.Factory.StartNew(async ()=> await InitAsync());
m_waitInitCompletedRequest.WaitOne(TimeSpan.FromSeconds(30));
return (int)EndpointErrorCode.Ended;
}
Everything now runs fine and I don't get any deadlocks.
For more details on the issues & answers, you may also refer to the edits in my question.

BreezeJS SaveChanges - undefined is not a function

I'm very new to BreezeJS and i'm doing something wrong, but not sure what. I am using a 3rd party API for my GET requests and using my own server backend to process the SaveChanges to fire off each request individually to the 3rd party as I can't customize the post/put requests to the exact syntax and post data format I need.
Our Model is dynamic (meaning customers can add new attributes/fields which then flow through from the rest api to our client) so that's why the code looks like it does below, this is the controller:
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
var context = JsonConvert.DeserializeObject<List<dynamic>>(saveBundle.SelectToken("entities").ToString());
foreach (var entity in context)
{
foreach (JProperty obj in entity)
{
if (obj != null)
{
// nothing right now but in future persist somehow
}
}
}
// Construct the save result to inform the client that the server has completed the save operation
var keyMappings = new List<KeyMapping>();
return new SaveResult()
{
Entities = context.Cast<object>().ToList(),
Errors = null,
KeyMappings = keyMappings
};
}
Call stack looks like such:
TypeError: undefined is not a function
at http://localhost:5749/Scripts/breeze.debug.js:14114:51
at http://localhost:5749/Scripts/breeze.debug.js:235:26
at Array.map (native)
at __map (http://localhost:5749/Scripts/breeze.debug.js:234:15)
at proto.visitAndMerge (http://localhost:5749/Scripts/breeze.debug.js:14111:16)
at http://localhost:5749/Scripts/breeze.debug.js:12806:48
at __using (http://localhost:5749/Scripts/breeze.debug.js:395:16)
at Object.processSavedEntities (http://localhost:5749/Scripts/breeze.debug.js:12794:13)
at saveSuccess (http://localhost:5749/Scripts/breeze.debug.js:12776:67)
at deferred.promise.then.wrappedCallback (http://localhost:5749/Scripts/angular.js:11046:81) undefined
I traced it to this line in proto.visitAndMerge (line 14114 in breeze.debug.js):
if (node.entityAspect.entityState.isDeleted()) {
If you think I'm doing something idiotic I'm all ears too. The third party API can be modified to do a GET accordingly but there is nothing to handle the SaveChanges bundle so as far as I know this is what I need to do.
Any advice would be great.
For reference, I was trying to follow this pattern: Breezejs SaveChanges: is it possible to return a custom SaveResult object, somehow?
I figured it out. entityAspect is sent along with the request. So converting it to a dynamic object created an entityAspect property which I then sent back to the client. This entityAspect needed to be removed so that it would not interfere with the JavaScript object.
Here's some code, maybe it helps someone someday:
var entities = JsonConvert.DeserializeObject<List<dynamic>>(saveBundle.SelectToken("entities").ToString());
foreach (var entity in entities)
{
JObject objEntityAspect = entity["entityAspect"];
JToken objEntityState = objEntityAspect["entityState"];
if (objEntityState.Value<string>() == "Modified")
{
// make a post with the instance id
}
entity.Remove("entityAspect");
}
entity.Remove("entityAspect") was the key component needed.

Invoke or Named Update?

I am using Silverlight with WCF RIA Services.
There is a class in my entity model called Activation. It has properties: Code1 and Code2 along with other properties.
On my silverlight client I need to send an Activation to the server where it picks out values from objects associated with it and populates the Code1 and Code1 attributes. E.g:
Public Sub ServerMethod(ByRef myActivation as Activation)
Dim x as Integer = myActivation.Licence.NumberOfDays
Dim y as Integer = myActivation.Product.ProductSeed
myActivation.Code1 = GetCode1(x,y)
myActivation.Code2 = GetCode2(x,y)
End Sub
Note that the activation codes are not persisted to the database, they simply go back to the client where the user can decide to save if they like from there.
What is the best way to achieve this using WCF RIA Services? At first I thought a named update in the domain service might do the job but there seems to be no Async callback for that.
Any ideas would be greatly appreciated!
It's exactly what the InvokeAttribute is meant for, just put it on your "ServerMethod". About the Async, every single call in wcf ria services is asynchronous and you have to supply a callback to the method if you want to be notified.
EDIT:
I didn't see in your question that you need to pass "Association" properties along the wire. In that case a NamedUpdate, though semantically incorrect, could be easier. Just remember that your context has to be "clean" or you'll submit unintended changes to the server (remember that you have to call the SubmitChanges on the DomainContext).
In case you prefer to use the InvokeAttribute, (and this is the way I'd go) then, yes, as you pointed out, return the "updated" entity to the client and to workaround the problem with the association, use Serialization on your own, i.e ,Serialize your entity and send it to the server, than Deserialize server side and serialize it again before return it to the client, where you'll finally deserialize it.
I'm attaching a piece of code that I use both server and client side that I use with this purpose.
public static class Serialization
{
public static string Serialize<T>(T obj)
{
//Create a stream to serialize the object to.
var ms = new MemoryStream();
// Serializer the User object to the stream.
var ser = new DataContractSerializer(typeof (T));
ser.WriteObject(ms, obj);
byte[] array = ms.ToArray();
ms.Close();
return Encoding.UTF8.GetString(array, 0, array.Length);
}
public static T Deserialize<T>(string obj) where T : class
{
if (obj == null)
return null;
var serializer = new DataContractSerializer(typeof (T));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(obj));
var result = serializer.ReadObject(stream) as T;
return result;
}
}
HTH

C# WCF closing channels and using functions Func<T>

This is the point, I have a WCF service, it is working now. So I begin to work on the client side. And when the application was running, then an exception showed up: timeout. So I began to read, there are many examples about how to keep the connection alive, but, also I found that the best way, is create channel, use it, and dispose it. And honestly, I liked that. So, now reading about the best way to close the channel, there are two links that could be useful to anybody who needs them:
1. Clean up clients, the right way
2. Using Func
In the first link, this is the example:
IIdentityService _identitySvc;
...
if (_identitySvc != null)
{
((IClientChannel)_identitySvc).Close();
((IDisposable)_identitySvc).Dispose();
_identitySvc = null;
}
So, if the channel is not null, then is closed, disposed, and assign null. But I have a little question. In this example the channel has a .Close() method, but, in my case, intellisense is not showing a Close() method. It only exists in the factory object. So I believe I have to write it. But, in the interface that has the contracts or the class that implemets it??. And, what should be doing this method??.
Now, the next link, this has something I haven't try before. Func<T>. And after reading the goal, it's quite interesting. It creates a funcion that with lambdas creates the channel, uses it, closes it, and dipose it. This example implements that function like a Using() statement. It's really good, and a excellent improvement. But, I need a little help, to be honest, I can't understand the function, so, a little explanatino from an expert will be very useful. This is the function:
TReturn UseService<TChannel, TReturn>(Func<TChannel, TReturn> code)
{
var chanFactory = GetCachedFactory<TChannel>();
TChannel channel = chanFactory.CreateChannel();
bool error = true;
try {
TReturn result = code(channel);
((IClientChannel)channel).Close();
error = false;
return result;
}
finally {
if (error) {
((IClientChannel)channel).Abort();
}
}
}
And this is how is being used:
int a = 1;
int b = 2;
int sum = UseService((ICalculator calc) => calc.Add(a, b));
Console.WriteLine(sum);
Yep, I think is really, really good, I'd like to understand it to use it in the project I have.
And, like always, I hope this could be helpful to a lot of people.
the UseService method accepts a delegate, which uses the channel to send request. The delegate has a parameter and a return value. You can put the call to WCF service in the delegate.
And in the UseService, it creates the channel and pass the channel to the delegate, which should be provided by you. After finishing the call, it closes the channel.
The proxy object implements more than just your contract - it also implements IClientChannel which allows control of the proxy lifetime
The code in the first example is not reliable - it will leak if the channel is already busted (e.g. the service has gone down in a session based interaction). As you can see in the second version, in the case of an error it calls Abort on the proxy which still cleans up the client side
You can also do this with an extension method as follows:
enum OnError
{
Throw,
DontThrow
}
static class ProxyExtensions
{
public static void CleanUp(this IClientChannel proxy, OnError errorBehavior)
{
try
{
proxy.Close();
}
catch
{
proxy.Abort();
if (errorBehavior == OnError.Throw)
{
throw;
}
}
}
}
However, the usage of this is a little cumbersome
((IClientChannel)proxy).CleanUp(OnError.DontThrow);
But you can make this more elegant if you make your own proxy interface that extends both your contract and IClientChannel
interface IPingProxy : IPing, IClientChannel
{
}
To answer the question left in the comment in Jason's answer, a simple example of GetCachedFactory may look like the below. The example looks up the endpoint to create by finding the endpoint in the config file with the "Contract" attribute equal to the ConfigurationName of the service the factory is to create.
ChannelFactory<T> GetCachedFactory<T>()
{
var endPointName = EndPointNameLookUp<T>();
return new ChannelFactory<T>(endPointName);
}
// Determines the name of the endpoint the factory will create by finding the endpoint in the config file which is the same as the type of the service the factory is to create
string EndPointNameLookUp<T>()
{
var contractName = LookUpContractName<T>();
foreach (ChannelEndpointElement serviceElement in ConfigFileEndPoints)
{
if (serviceElement.Contract == contractName) return serviceElement.Name;
}
return string.Empty;
}
// Retrieves the list of endpoints in the config file
ChannelEndpointElementCollection ConfigFileEndPoints
{
get
{
return ServiceModelSectionGroup.GetSectionGroup(
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None)).Client.Endpoints;
}
}
// Retrieves the ConfigurationName of the service being created by the factory
string LookUpContractName<T>()
{
var attributeNamedArguments = typeof (T).GetCustomAttributesData()
.Select(x => x.NamedArguments.SingleOrDefault(ConfigurationNameQuery));
var contractName = attributeNamedArguments.Single(ConfigurationNameQuery).TypedValue.Value.ToString();
return contractName;
}
Func<CustomAttributeNamedArgument, bool> ConfigurationNameQuery
{
get { return x => x.MemberInfo != null && x.MemberInfo.Name == "ConfigurationName"; }
}
A better solution though is to let an IoC container manage the creation of the client for you. For example, using autofac it would like the following. First you need to register the service like so:
var builder = new ContainerBuilder();
builder.Register(c => new ChannelFactory<ICalculator>("WSHttpBinding_ICalculator"))
.SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory<ICalculator>>().CreateChannel())
.UseWcfSafeRelease();
container = builder.Build();
Where "WSHttpBinding_ICalculator" is the name of the endpoint in the config file. Then later you can use the service like so:
using (var lifetime = container.BeginLifetimeScope())
{
var calc = lifetime.Resolve<IContentService>();
var sum = calc.Add(a, b);
Console.WriteLine(sum);
}

Categories