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
Related
I am currently writing an application where I am getting data from the DB and passing it to the object which will later be used to send the data off else where. The issue I am having in testing is that the data doesn't hold in the object as when it is used later, I get null value errors. I know we can store these in sessions, but I also know you can use objects and have done it before at previous jobs, but do not recall what I am missing to maintain the information. Would I need to pass the object(s) from method to method until the job is done?
the first sample here shows where it is prepping the object.
public void FtpInitialize()
{
_LogController.LogToFile(ValidateMessage.BeginInitialization);
//Loading FTPClient object with ClientInfo Object data we got from DataBase. FTPClient object is the object that sends the data.
_LogController.FTPTraceLogToFile();
ClientInfo = _RepositoryController.GetClientInfo(ClientInfo);
if (ClientInfo == null)
ClientInfo.ClientDataExists = false;
else
{
FTPClient.Host = ClientInfo.Host;
FTPClient.Port = ClientInfo.Port;
FTPClient.EncryptionMode = FtpEncryptionMode.Explicit;
FTPClient.Credentials = new NetworkCredential(ClientInfo.UserName, ClientInfo.Password);
FTPClient.DataConnectionType = FtpDataConnectionType.EPSV; //according library documentation, auto passive is broken as of 10/20/2016
FTPClient.EnableThreadSafeDataConnections = ClientInfo.EnableThreadSafeConnection;
FTPClient.DataConnectionConnectTimeout = ClientInfo.DataConnectionTimeout;
FTPClient.DataConnectionReadTimeout = ClientInfo.DataReadTimeout;
FTPClient.ConnectTimeout = ClientInfo.ConnectionTimeout;
FTPClient.ReadTimeout = ClientInfo.ReadTimeout;
FTPClient.SocketPollInterval = ClientInfo.SocketPollInterval;
FTPClient.SocketKeepAlive = ClientInfo.KeepSocketAlive;
FTPClient.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
_LogController.LogToFile(ValidateMessage.ClientDataLoaded);
ClientInfo.ClientDataExists = true;
}
}
then below when I hit this part, it shows as null
public bool SendData()
{
short errorCount = 0;
using (FTPClient)
{
if (ClientInfo.ClientDataExists)
{
This looks like you are using local variables in your methods. This is why the data "disappears".
For example if you are pulling data from your database you should have some kind of model class and container so that the data can persist until you are done with it.
EX: You have a database that contains information on people (name, dob, etc).
You should have a class that defines person and possibly a List to store said people. You call your database and pull X person objects into your List variable. You then can pass your List into the methods. Note: You can ditch the List (or whatever collection you use) if you are doing it one at a time.
The implementation of this really depends on how you want the objects to persist. If you know you will only pull one person object at a time you can declare var databasePerson from the database. Use the List if you will be pulling more information and then pop off the object when your are down with it.
Hope that helps.
i have a web api 2 project the client will request some data that is in a xml format. That XML will never change and i am wondering how i could keep it in ram so that it doesnt deserialize the xml each time it needs data from that file.
Would deserializing it at launch and then keep it in a static variable be the best way as it will only be use for reading ?
[HttpPost]
[Route("api/dosomething")]
public string DoSomething() {
var myData = XmlSerializer(MyDataStruct).Deserialize(something);
return myDate;
}
Here the xml is only used to communicate values to clients. How can i make it so that i could deserialize it once and then return that directly. Would using static member enable this feature ?
A simple cache-aside approach with a static field could be a fair option:
private static MyDataStruct _myData;
[HttpPost]
[Route("api/dosomething")]
public string DoSomething() {
if(_myData == null)
{
_myData = new XmlSerializer(typeof(MyDataStruct)).Deserialize(something);
}
return _myData;
}
If you want even better performance and completely skip both the deserialization from your XML and the serialization of your response body into JSON/XML, then I strongly suggest you an HTTP output caching approach, using a library like this one: AspNetWebApi-OutputCache.
In a generated Service Reference (imported from a WSDL), I have the following methods in the Client class, in the Reference.cs:
public Namespace.Service.SalesOrderDetail newService(Namespace.Service.Contact orderContact, Namespace.Service.Contact installationContact, string customerReference, Namespace.Service.ServiceDetails[] serviceDetailsList) {
Namespace.Service.newServiceRequest inValue = new Namespace.Service.newServiceRequest();
inValue.orderContact = orderContact;
inValue.installationContact = installationContact;
inValue.customerReference = customerReference;
inValue.serviceDetailsList = serviceDetailsList;
Namespace.Service.newServiceResponse retVal = ((Namespace.Service.ServiceRequestPortType)(this)).newService(inValue);
return retVal.salesOrder;
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
System.Threading.Tasks.Task<Namespace.Service.newServiceResponse> Namespace.Service.ServiceRequestPortType.newServiceAsync(Namespace.Service.newServiceRequest request) {
return base.Channel.newServiceAsync(request);
}
public System.Threading.Tasks.Task<Namespace.Service.newServiceResponse> newServiceAsync(Namespace.Service.Contact orderContact, Namespace.Service.Contact installationContact, string customerReference, Namespace.Service.ServiceDetails[] serviceDetailsList) {
Namespace.Service.newServiceRequest inValue = new Namespace.Service.newServiceRequest();
inValue.orderContact = orderContact;
inValue.installationContact = installationContact;
inValue.customerReference = customerReference;
inValue.serviceDetailsList = serviceDetailsList;
return ((Namespace.Service.ServiceRequestPortType)(this)).newServiceAsync(inValue);
}
I've seen Python code that uses the same WSDL, and it is able to access the method as response = client.newService(request).
I'd also like to access the method in that fashion, albeit var task = client.newService(request); Task.WaitAll(task); var response = task.Result;, but I can't seem to find the right combo of creating the service reference, without being forced to have expanded input parameters to the service.
Is there a magic combo for Service Reference creation that will allow me to just pass the request as a single object?
I'm not fussed on keeping the async functionality.
The client of a service implements the interface that represents the service. It just so happens, and is shown in this example, that it doesn't necessarily make all those implemented method public.
So, to get around this, if I cast the client object to the service interface, I get to call the service as intended, regardless of what the client has made public.
var client = new ServiceClient();
var service = (Service)client;
var request = new newServiceRequest() { ... };
var response = service.newService(request);
client.Close();
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.
I have a WebApi service that calculates a price of a customized product. The controller function is:
public double Get([FromUri]Specifications specifications)
Specifications is a class that allows to customize the product:
public class Specifications
{
public string Currency;
public int DesktopLicenses;
public Product Product;
public int Licenses;
}
Now, how can I consume this service from C#. I want to avoid to codify manually the URI query with all Specifications variables, I would like to able to use directly an instance of Specificationsto call the service.
If the service is a POST, I could do it doing:
Specifications product = new Specifications( ...);
HttpResponseMessage reponse = httpClient.PostAsJsonAsync("api/pricecalculator", product).Result;
but I cannot find the way to do the same when I use GET.
The example is showing that the GET is passing it a complex object in the call. Normally, that's just a simple request, and returning the complex object -- that's the "best practice". If you need to request something by giving it a complex object - it should still be a POST call. I know the pundits like to think POST/PUT as your change/add for the REST world -- but in the end, frankly there's zero difference between a POST and a GET besides the request body. If you need to give the server complex data, use the request body (aka POST). If it's a simple request -- /api/listofvendors/zone1 - then use a GET.
Web API Get Method with Complex Object as Parameter
example:
[HttpGet]
[Route("~/services/mrf/{mrfnumber}")] // GET specific MRF
public Mrf GetMrfRecord(string mrfnumber) {
using (var ddc = new MRFDataContext(ConnectionString)) {
var options = new DataLoadOptions();
options.LoadWith((Mrf c) => c.MRFParts); //immediate load related MRFParts
ddc.LoadOptions = options;
var mrf = (from u in ddc.Mrfs
where u.MrfNum == mrfnumber
select u).FirstOrDefault();
return mrf ?? null;
}
}