seems that Portable Class Library does not support PerSession (Wshttpbinding) required for this.
Is there any work around for this?
i have xamarin forms application (server client) that users can connect to their own database and get or update data.
once the user provide his username and password some information must be stored to their sessions like database connection string and when data request from user then the appropriate connection string that is stored to his session will be used for that database and send the data back.
otherwise without persession i have to pass on every function the connection string from the client.
how can i avoid this? Portable Class Library does not support wshttpbinding and therefore i cannot use PerSession
any help?
Too much Headache
The obstacles are too much for anyone working with the following combination
Xamarin Forms
PCL (Portable Class Libray)
WCF
IClientMessageInspector
The Problem:
I was need to have a multi client application that each one can connect to his own database ( same schema all )
For this purpose i was looking to store some information at a session level like (Connection String,User Information) so when a method called to know from which database i will retreive the data .
Problem # 1 ( took me 5 days to understand and realized)
that Sessions cannot be worked with PCL ( WCF PerSession) why? Because PerSession Needs WsHttpBinding but PCL Does not support WsHttpBinding only BasicHttp
Problem # 2 (took me 3 days to understand why is not working)
Then i saw many posts here and there about implementing IClientMessageInspector (see examples online how to implement IClientMessageInspector it's easy) so every time a client request a call to send some extra info to the server together with the call in my case was the connectionString. Here i was getting an exception that
NotImplementedException. Why? because of this BUG in MONO
https://bugzilla.xamarin.com/show_bug.cgi?id=40064
in simple words
When creating a WCF client in a PCL (targetting .NET Core) you must use EndpointBehaviors and not Behaviors. This works fine in a Windows RT application, but Mono has not implemented this so produces NotImplementedException in Android and iOS.
The answer is on the link above by another reply from someone else and i thank him for that .
In simple words
Instead of
MyService.Endpoint.EndpointBehaviors(New MyBehavior)
Use
Dim prop = MyService.Endpoint.GetType.GetTypeInfo.GetDeclaredProperty("Behaviors")
Dim obj = CType(prop.GetValue(MyService.Endpoint), KeyedCollection(Of Type, IEndpointBehavior))
obj.Add(New Behavior)
and instead of
clientRuntime.ClientMessageInspectors.Add(New MyInspector)
Use
Public Sub ApplyClientBehavior(endpoint As ServiceEndpoint, clientRuntime As ClientRuntime) Implements IEndpointBehavior.ApplyClientBehavior
Dim prop = clientRuntime.GetType.GetTypeInfo.GetDeclaredProperty("MessageInspectors")
Dim obj = CType(prop.GetValue(clientRuntime), ICollection(Of IClientMessageInspector))
obj.Add(New MyInspector)
End Sub
No changes needed to the configuration file
Hope this help someday someone.
Related
I'm building a multi-layered Windows VS C# solution that has a WCF Service Library project with EF6.2 loaded, and an ADO.NET Data layer with EF6.2 also.
The EDMX model is built as a 'database first' set of tables from my MSSQL Server Express 2016 server on my laptop. My WCF Service Interface and code
only have properties and methods for one of the tables at this point. And that table has also been built out in logic and data layer methods.
So, I'm testing that service now with the WCF Test Client, and I'm receiving some integer data correctly in my service's response from to the data layer, but no string data.
While testing my "GetMemberByID" method, it returns all String column results as a value of "(null)", and a type of "NullObject",
but returns Integers with their actual value. The WCF Soap response shows the returned String values as "". But,
the integers are returned like this: "7". There are over 50 data rows in my test database which is used as the source
for the EF6.2 EDMX build. My App.config's in data and service layers are referencing the same (localdb)\ V13.0 server and database.
Has anyone had this issue, and can you tell me what I'm missing? The MSSQL database was originally an (OleDb) MS Access database and I imported it into
MSSQL Server. Thanks in advance.
It seems that there is something wrong with the serialization process. On my side, the string field can be returned properly. By default, the DataContractSerializer is used to deserialize/deserialize the complex object data.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts
The most possible reason might be that the nullable field is not decorated by the [DataMember] attribute. Please check if the column of the DataContract autogenerated on the client-side contains the [DataMember] attribute.
http://sivakrishnakuchi.blogspot.com/2010/05/troubleshoot-wcf-service-returning.html
Feel free to let me know if the problem still exists.
Okay, I found my mistake. When translating the business domain objects back to the Service objects in the Service.cs code file, I was only translating the MemberID and the RowVersion - and no other columns. So, the only thing that was showing up in the WCF Test Client result was the MemberID and the RowVersion - which happen to be the only two non-strings in my entity. All the string types were null because I was not translating them back into the Service. Thanks for taking a look at this, Abraham, but you made me start looking closer, and thanks for the advice. The MS Documentation was helpful, too. Once I did a full "step into" debug trace from the UI through to the Data Layer and back, I was able to see the data translation failure. One more thing, before I could debug step by step all the way to the Data layer and back to the Service layer, I had to fix my "Underlying database did not open" issue that so many have had. I'm hosting my service through my local IIS, and had to make a few changes to the IIS application concerning the user credentials. My App.config is set to use "Integrated Security=True" - which is a "passthrough" credential in the IIS App pools. I had my IIS App set to "Specific User", but was not using a UserID/Password in my Connection String. Once I changed my IIS App to "Passthrough" - I was able to connect, and to debug to the DAL and back.
Sorry for the long question in the first place. I would rather prefer to come up with a shorter question but this is the most stripped version I could provide that I can clearly explain my point.
I have been trying to deliver a wrapper service to our client which should provide multiple services in it. Idea behind it is to reduce multiple calls to a one call and return a single object which has other associated objects in it. To illustrate my point, let me give following example:
Let's say we have following services:
MyCompany.Services.Donation
MyCompany.Services.Payment
MyCompany.Services.PartialPayment
Normally client should query Donation service (with a donationID) to get donation information, and then using the retrieved donation information, they should query Payment service to get payment related details, and if the payment is done in multiple small payments, using retrieved payment information, they should query PartialPayment service to get all donation information for a particular Donor.
Instead of client doing this, I am going to provide a wrapper service to accept donationID as a single parameter and return a class similar to this:
[DataContract(Namespace = "http://MyCompany.Services.DonationDetail")]
public class DonationDetail
{
[DataMember]
public MyCompany.Services.Donation.Record donationRecord;
[DataMember]
public PaymentDetail paymentDetail;
}
[DataContract(Namespace = "http://MyCompany.Services.DonationDetail")]
public class PaymentDetail
{
[DataMember]
public MyCompany.Services.Payment.Record paymentRecord;
[DataMember]
public List<MyCompany.Services.PartialPayment.Record> partialPayments;
}
So an instance of DonationDetail record should return all relevant information with that donation.
My problem arises when I use these individual services DLL's* in my wrapper service since any class I pass to client using wrapper service becomes part of the wrapper service and client can't use them right away with the corresponding types they retrieved using service references without writing a custom construction method to convert one type to another - although they are same objects. Instead of referring classes in original namespace, service uses following classes something like that now for the classes mentioned above:
DonationDetail.Record (Donation Record - I would expect MyCompany.Services.Donation.Record)
DonationDetail.Record1 (Payment Record - I would expect MyCompany.Services.Payment .Record)
DonationDetail.Record2 (PartialPayment Record - I would expect MyCompany.Services.PartialPayment.Record)
Is there a way to provide such an interface without a custom constructor? So, if they use "PartialPayment" namespace for the MyCompany.Services.PartialPayment WCF service, can they do something below after DonationDetail is retrieved via wrapper service?
PartialPayment.Record partialPayment = dDetailObj.paymentDetail.partialPayments[0];
*: Don't ask me why I don't use service references unless that is the cause of the problem, since that option gives me other problems to me at this point)
So I think what you are saying, effectively, is that if you have two different services that return the same object and when you add this as two different service references to the client, even though ultimately they are the same object as far as the services are concerned (since they reference the same DLL), the client sees them as two different types so you can't take the object returned from one and send it as the input to the other service.
Assuming I have understood your question (and I apologise if I have not)...
You could map one type to the other by constructing it and setting the properties but that is really kind of a pain and not very friendly to the consumer etc, hence I am going to suggest something kind of radical...
Ditch the service references on the client.
Yup, I said it, why would I suggest such a thing!?! Here's why...
First of all I would make sure my project was structured something like this:
Donation Detail Client Library
IDonationService (this is the service contract - notice no implementation in the client library)
DonationRecord
Payment Detail Client Library
IPaymentService (this is the service contract - notice no implementation in the client library)
PaymentRecord
Partial Payment Client Library
IPartialPaymentService (this is the service contract - notice no implementation in the client library)
PartialPaymentRecord
Wrapper Service Client Library (which references the three other client libraries)
IWrapperService (this is the service contract - notice no implementation in the client library)
Incidentally, I gave your records different class names but you could use namespaces if you like and call them all Record (I think calling them different names is less confusing, but that is probably just me).
On the service end you reference the client library that you need to implement the service and do whatever you have to do just as you always have.
On the client you reference the client libary (or libraries depending on what service you want to call) too, in the same way (so you effectively have a shared library between server and client - yeah old skool, but hey, you will see why).
The client then has the interface for the service contract and all the data contracts so it does not need the whole service reference, generated code thing. Instead what you can do on your client is something like this:
DonationRecord donation;
using (var cf = new ChannelFactory<IDonationService>("EndpointNameInConfigurationFile"))
{
IDonationService donationservice = cf.CreateChannel();
donation = donationservice.GetDonation("Donation1234");
}
using (var cf = new ChannelFactory<IWrapperService>("EndpointNameInConfigurationFile"))
{
IWrapperService wrapperService = cf.CreateChannel();
wrapperService.DoSomethingWithDonation(donation);
}
There, you see I took the data contract from one service and sent it to a completely unrelated service and it looks natural (I have an object that is returned from a method on class X and I took it and passed it as an agrument on class Y, job done, just like programming).
NOTE: Using this technique will not stop service references from working just as they always have so any existing client code would not have to change, just if you use your new wrapper service, you could use it like this to save having to map types.
I have a WCF Restful Service that returns JSON objects that my iPhone and Android apps consume nicely. This is my first attempt at building something like this and I left WP7 till last as my background lies with C# and VS2010. But it seems it’s not going to be a simple as I had guessed.
So I guess I have three questions:
1, Can I consume JSON objects in WP7? If so does anyone know of a tutorial?
2, if not, can I use the existing service and build some new contracts for consumption in WP7? Or,
3, do I need to build a whole new service?
Option one is most desirable but either way, I need to develop for all three operating systems so does anyone know the best type of model to bring this all together???
Cheers,
Mike.
Yes, but not with the channel factory / proxy programming model which you may be used to with WCF. REST services are usually consumed by using some simpler classes such as WebClient. You can use the JSON libraries (DataContractJsonSerializer is in the WP7 profile) then to deserialize the data you receive. Even the untyped JSON (the System.Json classes from the System.Json.dll on Silverlight), while not officially in the profile, they kind of work on WP7 as well (I've seen a few people simply referencing the SL library on a WP7 project).
If you want proxy support, you can add a new endpoint to the service using BasicHttpBinding, which is supported in WP7; if you don't need it, see 1).
No. See 1) and 2).
Try this to deserialize a JSON object:
public static T Deserialize<T>(string strData) where T : class
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
byte[] byteArray = Encoding.UTF8.GetBytes(strData);
MemoryStream memoryStream = new MemoryStream(byteArray);
T tRet = serializer.ReadObject(memoryStream) as T;
memoryStream.Dispose();
return tRet;
}
I find a totally wcf-based approach more interesting.
This is a good post that addresses this issue
http://blogs.msdn.com/b/carlosfigueira/archive/2010/04/29/consuming-rest-json-services-in-silverlight-4.aspx
From a little bit of reading around, it is my understanding that the only way to detect that a client has connected to my service is through writing my own code. I am using a Singleton service. I would like to display a message every time a client connects to my service that client x with ip xxx has connected. There is no built-in event that is generated? Am I correct?
No, I don't think there's any support in WCF for your requirement.
Not sure what you want to achieve with this, either. Your service class (in your case, just a single instance) really doesn't have any business putting up messages (on screen, I presume) - that really not it's job. The service class is used to handle a request and deliver a response - nothing more.
The ServiceHost class might be more of a candidate for this feature - but again, it's job really is to host the service, spin up the WCF runtime etc. - and it's really not a UI component, either.
What you could possibly do is this
have an Admin UI (a Winforms, console, or WPF app) running on your server alongside your service, providing an admin service to call
define a fast connection between the two services (using e.g. netNamedPipe binding which is perfect for intra-application messaging)
when your "real" service gets a call, the first thing it does is send out a message to the admin UI which can then pick up that message and handle it
That way, you could cleanly separate your real service and it's job (to provide that service) and the Admin UI stuff you want to do and build a cleanly separated system.
I have actually implemented my own connect, disconnect and ping service methods which I manually call from my client once the channel has been created. By using them as a kind of header section in all of my ServiceContract interface definitions (and their implementations, of course), they form an makeshift "base service definition" that only requires a bit of cut-n-paste.
The string-based parameters of connect and disconnect will be used to send client info to the server and return server info and (perhaps a unique connection id) to the client. In addition a set of timing reference points may make its way in also.
Note how SessionMode is required and the individual OperationContract properties IsInitiating and IsTerminating are explicitly specified for each method, the end result being what I would call a "single-session" service in that it defines connect and disconnect as the sole session bookends.
Note also that the ping command will be used as the target of a timer-based "heartbeat" call that tests the service connection state and defeats ALL connection timeouts without a single config file :-)
Note also that I haven't determined my fault-handling structure yet which may very well add a method or more and/or require other kinds of changes.
[ServiceContract( SessionMode = SessionMode.Required )]
public interface IRePropDalSvr {
[OperationContract( IsInitiating=true, IsTerminating=false )]
string connect (string pClientInfo);
[OperationContract( IsInitiating=false, IsTerminating=true, IsOneWay=true )]
void disconnect (string pClientInfo);
// ------------------------------------------------------------------------------------------
[OperationContract( IsInitiating=false, IsTerminating=false )]
string ping (string pInp);
// ------------------------------------------------------------------------------------------
// REST OF ServiceContract DEFINITION GOES HERE
One caveat: while I am currently using this code and its implemention in my service classes, I have not verified the code yet.
I have a Windows forms project and a Web Service project in my solution, and I'm trying to call the web service and return a customer object as the result. The problem is that when I try to receive the return object, I get an error that it can't convert it. For example, here is the signature for my webservice:
Public Function GetDriverByID(ByVal DriverID As Integer) As Driver
And here is the code I'm using to call it:
Dim d As Driver = mywebserviceinstance.GetDriverByID(1)
But I receive this compile-time error (wsDrivers is the name of the web reference I've added to my form project): "Value of type ProjectNamespace.Common.wsDrivers.Driver cannot be converted to ProjectNamespace.Common.Driver"
This "Common" namespace contains the Driver class, and I'm not sure why the return class from the web service isn't just a generic "Driver", but is instead a "wsDrivers.Driver", and I can't convert it back. Anybody know how I can deal with this type mismatch?
EDIT: Thanks for the explanations - this actually makes it clear what it's doing. However, is there any way that I can force it to use the actual type instead of the proxy (or, rather, is there any way to convert between the "real" instance and the "proxy" instance), or do I have to serialize the properties before I send them over the wire, and then manually de-serialize the return values?
This is actually pretty common. What's happening is that the Web Service has defined in it the definitions of all the types used in the web service. When you add a reference to that web service, it auto-generates a proxy type in a sub namespace of your namespace. That is what is being returned by your web service when you call it.
However, you probably are also referencing the same library that the web service does seperately that contains the same type. That is the type that is expected when you Dim Driver. That's why there is a mismatch.
The web service reference in a VB.NET or C# project can reference any type of web service and is not limited to those provided by ASP.NET. That is why Visual Studio creates proxy classes for each object which can be retrieved from the web service.