WCF: Best practice to send Form Data to a Web Service? - c#

We are using C#, ASP.NET & WCF. I am trying to send form data to a web service which in turn inserts/updates a database with the data from my form. How should I send over my data?
We have the forms populated fine but are having some issues with sending updates back to the web service. We have determined that it is not great practice to use datasets in this situation, it is slow and we have to do too many SELECT *'s for our liking.
I have about 15 fields that need to go across. One team member wants to pass everything as a parameter which I dont think is optimal. We tried sending everything across in an Object[] array but are receiving a weird error "Type 'System.DBNull' with data contract name 'DBNull:http...' is not expected. Add any types not known statically to the list of known types",
Any suggestions are most welcome.

We use WCF to define our Data Contracts and Data Methods using attributes.
Basically we create an assembly to define all our classes and another assembly to provide the WCF connective bits
OPur class assembly contains a service class and several message classes.
We define an interface for our service and mark it up with relevant WCF markup. This is our Service Contract.
[ServiceContract]
public interface IExampleWebService
{
[OperationContract]
CreateAccountResponse CreateAccount(int parameter, CreateAccountArguments another parameter);
[OperationContract]
DeleteAccountResponse DeleteAccount(int parameter);
}
We implement this interface in a class and we create various data contracts (our response and argument classes).
[DataContract]
public class CreateAccountResponse
{
[DataMember]
public bool CreatedOk { get; set; }
[DataMember]
public int AccountId { get; set; }
}
These classes are exposed to our form using the Web Service (We create another assembly as a web service and have a class that inherits from our Service Class (not shown in this example) so we let Visual Studio do all the work setting up the WCF service as we reap the benefits with an easy to use and maintain Web Service.

Related

Send devExpress Session as parameter in wcf service

I have an exception when I want to send a devExpress session in a composite type in WCF.
I tried to make it serializable but I still get the error
information: Type System.Data.SqlClient.SqlConnection with data
contract name
SqlConnection:http://schemas.datacontract.org/2004/07/System.Data.SqlClient
is not expected. Consider using a DataContractResolver if you are
using DataContractSerializer or add any types not known statically to
the list of known types - for example, by using the KnownTypeAttribute
attribute or by adding them to the list of known types passed to the
serializer.
This the DataContract That I used.
[DataContract]
[Serializable]
[ServiceKnownType(typeof(Session))]
[ServiceKnownType(typeof(SqlConnection))]
[ServiceKnownType(typeof(SqlParameter))]
public class CompositeType
{
Session sValue ;
[DataMember]
public Session SessionValue
{ get {return sValue; } set {sValue = value; } }
}
I use also a method that send this class as parameter
void GetDataUsingDataContract(CompositeType composite);
XPO objects are tied to the data store via Session and you cannot send them over the wire.
If you want just to transfer raw data between computers, use a Data Transfer Object. XPO will retrieve data from the database on one side, and you will retrieve the data on the other side using WCF client methods.
XPO also supports a more complex scenario. If you want to use XPO on the client side but cannot create a direct database connection for security reasons, you can implement the IDataStore interface as a contract on the WCF side.
It is easy to implement the IDataStore interface, because all you need is to wrap an existing Data Store Adapter. All Data Store Adapters implement the IDataStore interface. XPO's Data Access Layer can use any IDataStore as a data source. This blog explains this approach: XPO is good for distributed applications.
Moreover, XPO has built-in WCF service and client components that already implement the IDataStore interface. All you need is to put them together. See examples here: Transferring Data via WCF Services.

Can I use a web api from a web application as a service reference?

Is it possible to add as a reference and call an APIs controller methods as a service on another project? What are the alternatives if this is not possible?
Web API types of applications do not have a 'service reference' anymore. They do not produce WSDL, so you cannot add them like you used to do with SOAP services. No proxy classes are generated... no intelli-sense.
Web APIs are typically called with lightweight http requests and return JSON and not XML based SOAP responses like traditional ASMX or SVC (WCF) services.
You have some reading to do I believe.
To answer your question, you CAN indeed call API services from a web application (say a controller method in an MVC app), but you won't have proxy classes to help you.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
When you create a service reference you end up with a reference to an interface and a client class that implements the interface.
You can follow pretty much the same pattern without a WCF service reference. In fact, that's one of the benefits of depending on an interface. It doesn't matter to your application whether the implementation is a call to a WCF service, an API, or anything else.
First declare an interface that describes how you will interact with the API.
public interface ISomethingService
{
public SomeData GetSomeData(string id);
}
That interface is what your other classes depend on. They'll never know what the implementation is.
Your implementation could be something like this. I'm using RestSharp to create the API client because I like it better than managing an HttpClient:
public class SomethingServiceApiClient : ISomethingService
{
private readonly string _baseUrl;
public SomethingServiceApiClient(string baseUrl)
{
_baseUrl = baseUrl;
}
public SomeData GetSomeData(string id)
{
var client = new RestClient(_baseUrl);
var request = new RestRequest($"something/{id}", Method.POST);
var response = client.Execute<SomeData>(request);
return response.Data;
}
}
In your startup you would register this class as the implementation of ISomethingService and pass the base url from configuration. That would also allow you to pass a different url for development, production, etc. if needed.
Ultimately it's no different from depending on a WCF service. One difference is that a WCF service defines an interface, but in this case you have to do it. That's actually a good thing, because it's better for your application to define its own interface rather than directly depending on the ones someone else provides. You can wrap their interface or API in a class that implements your own interface, giving you control over the interface you depend on.

How can I work against two different versions of a web service?

My project is a consumer for a 3rd party web service (old school web service vs. WCF service), and it has two versions, the "sandbox" (staging), and prod services. The APIs on these services are almost identical, and I am looking for a way to cleanly switch between the two versions, preferably without using conditional compilation.
I instinctively rushed off and extracted an interface from the client generated by Visual Studio's "Add web reference", i.e. AgentImport but that class is not partial, so I can't make it derive from the interface, or from any other superclass. I already have the creation of AgentImport instances nicely encapsulated in an abstract base for all my clients of AgentImport, but without using more risky compiler directives, how can I switch between v1 and v2 of AgentImport?
Some code:
using Clients.PrivateProperty.AgencyServicesApiService;
namespace Client.PrivateProperty
{
public abstract class PrivPropFacilityBase
{
protected static AgentImport Client;
protected PrivPropFacilityBase()
{
Client = new AgentImport();
Client.Timeout = 10000;
}
protected virtual AgentImport GetClient()
{
return new AgentImport();
}
}
}
I have tried adding service references instead of web references, as advised in comments below, to at least get access to partial classes, but when I add the first service reference, for the production service, and extract an interface from the auto-generated SOAP client, i.e. IAsapiClient, that interface references objects declared in other auto-generated classes, in the same namespace as the client, e.g. SecurityToken:
void UpdateUniqueAgentID(string PrivatePropertyAgentId, string AgentId, AgencyServicesApiService.SecurityToken Token);
If I add the second service reference, for the staging service, that second auto-generated SOAP client references objects in its own namespace, e.g. now it uses AgencyServicesApiSandbox.SecurityToken, so my compiler tells me that it doesn't implement the interface I extracted the first time. I am then left with the messy business of having to extract an new interface for each object that the main interface, IAsapiClient, references, so that this main interface only uses the extracted contracts, not actual class names.
In pursuing the above< I have reached the conclusion that my only feasible, and lowest risk, way forward is to use two client projects, one specifically for the production service, and one for the staging service. Then, at execution time, I only need to worry about dynamically choosing between two well known, i.e. not auto-generated, client objects.

Secure and loose coupled communication between clients and WCF services using a RoutingService in between

Is it possible to send objects through RoutingService to peer WCF services without having the router know about the exact type of these objects ?
My intention is to create a router once for all, then be able to add new WCF services, dynamically add them to the routing table, and allow clients to communicate with these services without having to stop, change the code of the router, then start it again.
I was thinking of a generic contract like this:
[DataContract]
public class RequestObject
{
}
[DataContract]
public class ReplyObject
{
}
[ServiceContract]
public interface IGenericServiceInterface
{
[OperationContract]
ReplyObject DoJob(string jobType, RequestObject request);
}
I could put this in a common library that all 3 components link to (client, router, services). But, I am not sure, it will be possible to derive new sub classes to allow new clients/services with new data exchanges to be added without having to change the router.
Any advise ? is it possible for the solution to work when encryption is enforced through clients till services ?
Thanks in advance.
There's a good msdn on using the Message class in WCF to build contract agnostic endpoints. Does not use routing service, but you could build a router using this:
http://msdn.microsoft.com/en-us/library/ms734675.aspx

Streamed transfer restrictions with WCF

According to the following guide at MSDN, any operations that use streamed transfers can only have one input/output parameter.
Link: http://msdn.microsoft.com/en-us/library/ms731913.aspx (see heading "Restrictions on Streamed Transfers")
I'm using streamed transfers for a WCF service that lets clients/consumers upload files to it. The upload itself works fine, but I need a way of passing two more input parameters along with the Stream object: 'string filename' and 'int userid'.
How would I go about doing this?
ThereĀ“s something called headers that you can use in your datacontract:
Example of the interface:
[ServiceContract]
public interface IFile
{
[OperationContract]
Stream DownloadFile(int fileid);
[OperationContract]
bool UploadFile(FileUploadMessage request);
}
Put this in a separate file:
[MessageContract]
public class FileUploadMessage
{
[MessageHeader(MustUnderstand = true)]
public int MyInt {get;set;
[MessageHeader(MustUnderstand = true)]
public string MyString {get;set;
[MessageBodyMember(Order = 1)]
public System.IO.Stream FileByteStream {get;set;}
}
I have a somewhat similar problem. I created a test project and used a post I found to successfully create a wcf service call it from another project. I have a solution and the two web projects. One project call the service in the other project using a service reference.
I had the ServiceContract and the message contract in the interface file generated by creating a wcf service (the file that start with "I"). All of this worked fine. Then I went to our company's main project. It has a main web project that hosts two silverlight project. However the web project is not really a project but started out life as a website with no project at all. I have assumed that adding the two silverlight projects to the website probably created a solution for all three projects. However I'm not certain how vs2010 sees the main website which I will assume has no pointers to any files as a "real" project would.
What happened was when I created the wcf service in the main website and put the ServiceContract and MessageContract into the interface file I got the "interfaces cannot declare types" messge regarding the MessageContract and its child classes. I'm trying to follow your advice onthis post by taking the MessageContract and putting it into another file but I'm not sure what type of file. I tried putting the Message contract into a class (cs file). However the ServiceContract refers to classes in the MessageContract and the ServiceContract is no longer seeing the classes in the MessageContract even though they are public.
What type of file should I use to separate the Message contract from the ServiceContract?
Thanks,
Fig

Categories

Resources