Calling webservice with complex parameters from c# client - webservices-client

Hello, Here is a class ...
public class Authentification
{
private string userField;
private string passwordField;
public string user
{
get
{
return this.userField;
}
set
{
this.userField = value;
}
}
public string password
{
get
{
return this.passwordField;
}
set
{
this.passwordField = value;
}
}
}
here the web service :
[WebMethod]
public Vehicle[] getVehiculeList(Authentification authentification)
{
....
}
Here the client and the call of webservice :
(the same class Authentification like in the webservice has been defined)
Authentification azz = new Authentification() ;
azz.user = "toto";
azz.password = "tata";
string aa = ws.getVehiculeList(azz);
gives an error :
Error 27 The best overloaded method match for 'WSCL.localhost.Service1.getVehiculeList(WSCL.localhost.Authentification)' has some invalid arguments
and
Error 28 Argument '1': cannot convert from 'WSCL.Authentification' to 'WSCL.localhost.Authentification'
Any help ?
Thank a lot !

What might have happened is that you have referenced the assembly containing the data entities (e.g. Authentication) on your client, and now you have both the proxied entity (WSCL.localhost.Authentification) and the original server entity (WSCL.Authentification). If you change your client's use of Authentication to use the proxied class (WSCL.localhost.Authentification) it should work.
If you switch to WCF, you will be able to move the data entities like Authentication into a separate assembly, and then Share this same type between your Service and your Client. AFAIK this isn't possible 'out of the box' in ASMX.

Related

WCF operation in Client expects a different sets of argument than what is defined in server

I am new to WCF. I have a sample WCF server and a client consuming the service.
I have a OperationContract called getEmployer4 which accepts a EmployerRequestBO and returns a EmployerResponseBO, both these 2 types are decorated as MessageContract
public EmployerResponseBO getEmployer4(EmployerRequestBO rqst)
{
return new EmployerResponseBO
{ CompanyName = "Apple", CompanyAddress = "US" };
}
my EmployerRequestBO looks like:
[MessageContract(IsWrapped = true, WrapperName = "EmployerRequest", WrapperNamespace ="http://mycompany.com/services")]
public class EmployerRequestBO
{
[MessageHeader(Namespace = "http://mycompany.com/services")]
public string LicenseKey
{
get; set;
}
private int _regID;
[MessageBodyMember(Order = 1, Name = "CompanyRegistrationID", Namespace = "http://mycompany.com/services")]
public int RegistrationID
{
get
{
return _regID;
}
set
{
_regID = value;
}
}
Problem is, when i tried to call the operaiton in client with below code:
ServiceReference_EmployerService.EmployerClient client = new ServiceReference_EmployerService.EmployerClient("BasicHttpBinding_IEmployer");
ServiceReference_EmployerService.EmployerRequestBO request = new ServiceReference_EmployerService.EmployerRequestBO("ABC123", 123);
ServiceReference_EmployerService.EmployerResponseBO response= client.getEmployer4(request);
The getEmployer4 doesnot expect an EmployerRequestBO argument, Error looks like below
Click to see attachment
There is no argument given that corresponds to the required formal
parameter 'CompanyRegistrationID' of
'EmployerClient.GetEmployer4(string, ref int, out string)'.
Can anyone explain why it is asking for primitive types instead of a MessageContract type? Thanks!
It took quite a bit of time before I learned that, if your Operation communicate through MessageContract, you need to create the proxy like:
ServiceReference_EmployerService.**IEmployer** client =
new ServiceReference_EmployerService.EmployerClient("BasicHttpBinding_IEmployer");
whereas if you Operation communicate through DataContract, you need to create the proxy like:
ServiceReference_EmployerService.**EmployerClient** client2 =
new ServiceReference_EmployerService.EmployerClient("BasicHttpBinding_IEmployer");

Spring Cloud FeignClient decoding application/hal+json Resource<Object> return type

I'm developing a REST API using Spring Cloud, Spring Data JPA, Spring Data Rest and Spring Boot. The server implementation generates the various data items correctly, according to the HAL spec and so forth. It generates the HAL+JSON as follows:
{
"lastModifiedBy" : "unknown",
"lastModifiedOn" : "2015-06-04T12:19:45.249688",
"id" : 2,
"name" : "Item 2",
"description" : null,
"_links" : {
"self" : {
"href" : "http://localhost:8080/pltm/accounts/2"
},
"customers" : {
"href" : "http://localhost:8080/pltm/accounts/2/customers"
},
"users" : {
"href" : "http://localhost:8080/pltm/accounts/2/users"
},
"groups" : {
"href" : "http://localhost:8080/pltm/accounts/2/groups"
}
}
}
Now I'm trying to implement the client implementation, using the FeignClient Spring Cloud library. I've defined my client interface as follows.
#FeignClient("serviceId")
#RequestMapping(value = "/api", consumes = MediaType.APPLICATION_JSON_VALUE)
public interface PltmClient
{
// Account Requests
#RequestMapping(method = RequestMethod.GET, value = "/accounts")
PagedResources<Resource<Account>> getAccounts();
#RequestMapping(method = RequestMethod.GET, value = "/accounts/{id}")
Resource<Account> getAccountAsResource(#PathVariable("id") Long id);
#RequestMapping(method = RequestMethod.GET, value = "/accounts/{id}")
Account getAccount(#PathVariable("id") Long id);
}
When I call the getAccout() method, I get back my domain object Account with the details from the JSON document. That object is a simple POJO. All of the fields are filled in properly.
public class Account
{
private Long id;
private String name;
private String description;
/** Setters/Getters left out for brevity **/
}
But when I call the getAccountAsResource(), it works and I get back a Resource object that has the data. However, the call to Resource.getContent() returns an Account object that is not completely filled out. In this case, the Account.getId() is NULL, which is causing problems.
Any ideas why this is happening? One idea I had is that the Resource class defines a getId() method, and that is somehow confusing the Jackson ObjectMapper.
The larger question is if this whole method is viable or is there a better way? Obviously, I could just use the plain POJO as my return type, but that looses the HAL information on the client side.
Has anyone successfully implemented a Java-based client implementation for Spring Data REST server endpoints?
Account not having an id is a feature of spring-data-rest. You need to enable populating of the id on the server side.
I also add a different method to return the id (in Account)
#JsonProperty("accountId")
public String getId() {
return id;
}
Enable id
#Configuration
public class MyConfig extends RepositoryRestMvcConfiguration {
#Override
protected void configureRepositoryRestConfiguration( RepositoryRestConfiguration config) {
config.exposeIdsFor(Account.class);
}
}
I have used it here: https://github.com/spencergibb/myfeed, though I believe where I use resources, I'm using RestTemplate.

How to implement a Restlet JAX-RS handler which is a thin proxy to a RESTful API, possibly implemented in the same java process?

We have two RESTful APIs - one is internal and another one is public, the two being implemented by different jars. The public API sort of wraps the internal one, performing the following steps:
Do some work
Call internal API
Do some work
Return the response to the user
It may happen (though not necessarily) that the two jars run in the same Java process.
We are using Restlet with the JAX-RS extension.
Here is an example of a simple public API implementation, which just forwards to the internal API:
#PUT
#Path("abc")
public MyResult method1(#Context UriInfo uriInfo, InputStream body) throws Exception {
String url = uriInfo.getAbsolutePath().toString().replace("/api/", "/internalapi/");
RestletClientResponse<MyResult> reply = WebClient.put(url, body, MyResult.class);
RestletUtils.addResponseHeaders(reply.responseHeaders);
return reply.returnObject;
}
Where WebClient.put is:
public class WebClient {
public static <T> RestletClientResponse<T> put(String url, Object body, Class<T> returnType) throws Exception {
Response restletResponse = Response.getCurrent();
ClientResource resource = new ClientResource(url);
Representation reply = null;
try {
Client timeoutClient = new Client(Protocol.HTTP);
timeoutClient.setConnectTimeout(30000);
resource.setNext(timeoutClient);
reply = resource.put(body, MediaType.APPLICATION_JSON);
T result = new JacksonConverter().toObject(new JacksonRepresentation<T>(reply, returnType), returnType, resource);
Status status = resource.getStatus();
return new RestletClientResponse<T>(result, (Form)resource.getResponseAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS), status);
} finally {
if (reply != null) {
reply.release();
}
resource.release();
Response.setCurrent(restletResponse);
}
}
}
and RestletClientResponse<T> is:
public class RestletClientResponse<T> {
public T returnObject = null;
public Form responseHeaders = null;
public Status status = null;
public RestletClientResponse(T returnObject, Form responseHeaders, Status status) {
this.returnObject = returnObject;
this.responseHeaders = responseHeaders;
this.status = status;
}
}
and RestletUtils.addResponseHeaders is:
public class RestletUtils {
public static void addResponseHeader(String key, Object value) {
Form responseHeaders = (Form)org.restlet.Response.getCurrent().getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS);
if (responseHeaders == null) {
responseHeaders = new Form();
org.restlet.Response.getCurrent().getAttributes().put(HeaderConstants.ATTRIBUTE_HEADERS, responseHeaders);
}
responseHeaders.add(key, value.toString());
}
public static void addResponseHeaders(Form responseHeaders) {
for (String headerKey : responseHeaders.getNames()) {
RestletUtils.addResponseHeader(headerKey, responseHeaders.getValues(headerKey));
}
}
}
The problem is that if the two jars run in the same Java process, then an exception thrown from the internal API is not routed to the JAX-RS exception mapper of the internal API - the exception propagates up to the public API and is translated to the Internal Server Error (500).
Which means I am doing it wrong. So, my question is how do I invoke the internal RESTful API from within the public API implementation given the constraint that both the client and the server may run in the same Java process.
Surely, there are other problems, but I have a feeling that fixing the one I have just described is going to fix others as well.
The problem has nothing to do with the fact that both internal and public JARs are in the same JVM. They are perfectly separated by WebResource.put() method, which creates a new HTTP session. So, an exception in the internal API doesn't propagate to the public API.
The internal server error in the public API is caused by the post-processing mechanism, which interprets the output of the internal API and crashes for some reason. Don't blame the internal API, it is perfectly isolated and can't cause any troubles (even though it's in the same JVM).

How to properly handle WCF faults with Silverlight?

No matter how hard I try I cannot seem to be able to handle WCF faults in Silverlight.
In fact the error seems to never leave the server !
E.g. when I debug it, it stops on the line where I throw the FaultException saying it was not handled:
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class StoreService : IStoreContract
{
public System.Collections.Generic.List<string> GetStoreDesignNames()
{
try
{
StoreDataContext swdc = new StoreDataContext();
var query = from storeDesign in swdc.StoreDesignDBs select storeDesign.Name;
return query.ToList();
}
catch (System.Data.SqlClient.SqlException sqlExcept)
{
throw new FaultException<SqlFault>(new SqlFault() { Message = sqlExcept.Message });
}
}
}
The class that implements this method derives from a contract interface:
[ServiceContract(Namespace = "Store")]
public interface IStoreContract
{
/// <summary>
/// Obtain the list of store design names.
/// </summary>
[OperationContract,
FaultContract(typeof(SqlFault))]
List<String> GetStoreDesignNames();
}
And the SqlFault class is defined like this:
public class SqlFault
{
public String Message { get; set; }
}
On the client side I handle the error as follow:
// swc is the client
swc.GetStoreDesignNamesCompleted += new EventHandler<ServiceReference.GetStoreDesignNamesCompletedEventArgs>((obj, evt) =>
{
if (evt.Error == null)
{
// In case of success
MessageBox.Show(evt.Result.First());
}
else if (evt.Error is FaultException<ServiceReference.SqlFault>)
{
FaultException<ServiceReference.SqlFault> fault = evt.Error as FaultException<ServiceReference.SqlFault>;
Dispatcher.BeginInvoke(() =>
{
ErrorWindow ew = new ErrorWindow(fault.Detail.Message, "No details");
ew.Show();
});
}
});
swc.GetStoreDesignNamesAsync();
I have tried to put the [SilverlightFaultBehavior] attribute on the interface, to no avail. Even if I do without the interface I still have this error.
I have also tried to use a behavior extension in the web.config as described here but I get a warning saying the extension is not valid.
How does one go about properly handling WCF fault in Siverlight ?
Thanks in advance.
I haven't used WCF (been using WCF RIA Services) but I did come across this article a while ago.
Getting something better than “Server not found.” from WCF in Silverlight
After battling with this for hours I finally hacked something together that works.
This is really a horrible hack and I would have much preferred to use BehaviorExtension for this task. The trick is to set manually the HTTP status code in the body of the WCF method like so:
public System.Collections.Generic.List<string> GetStoreDesignNames()
{
try
{
StoreDataContext swdc = new StoreDataContext();
var query = from storeDesign in swdc.StoreDesignDBs select storeDesign.Name;
return query.ToList();
}
catch (System.Data.SqlClient.SqlException sqlExcept)
{
System.ServiceModel.Web.WebOperationContext ctx = System.ServiceModel.Web.WebOperationContext.Current;
ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
throw new FaultException<SqlFault>(new SqlFault() { Message = sqlExcept.Message });
}
}
The error message then correctly displays on the client side.
If anybody has a better solution than this I'd like to hear it.

Message or a type that has MessageContractAttribute and other parameters of different types

I'm developing WCF services where some classes have the [MessageContract] attribute, and some don't.
When I try to run the services I get this error message below:
The operation 'ProcessOperation' could not be loaded because it has a parameter or return type of type System.ServiceModel.Channels.Message or a type that has MessageContractAttribute and other parameters of different types. When using System.ServiceModel.Channels.Message or types with MessageContractAttribute, the method must not use any other types of parameters.
Does it mean that all the services must have [MessageContract] although they are not related?
No, it means that you have multiple parameters on the method and some of them are not messages. Try posting the interface to your service.
This blog post explains:
... problem is that message contracts cannot be used at the same time as other parameter types. In this case, the return value of the operation is a string. Return values are just another output parameter, so this operation is mixing a message contract message with a primitive parameter type. This fails because message contracts give you control of the layout of the SOAP message, preventing the system from melding in these additional parameters.
Important note:
By the way, the error message you get when you try to mix message contracts looks like this.
This basically means that a particular operation is using a combination of message contract types and primitive types in any of the following combinations:
MixType1: Contract type and primitive types as operation parameters
MixType2: Contract type as a parameter and primitive type as return type
MixType3: Primitive type as a parameter and Contract type as return type
Any of the scenarios listed above would generate the error.
Solved!
I can't return String, I have return Greeting object to the client.
using System;
using System.ServiceModel;
using System.Net.Security;
namespace com.blogspot.jeanjmichel.model
{
[MessageContract]
public class Greeting
{
private String userGreeting;
private void SetGreeting()
{
DateTime now = DateTime.Now;
if (now.Hour >= 7 && now.Hour <= 11)
{
this.userGreeting = "Good morning";
}
else if (now.Hour >= 12 && now.Hour <= 17)
{
if (now.Hour == 12 || now.Hour == 13)
{
this.userGreeting = "Good afternoon, it's lunch time!";
}
else
{
this.userGreeting = "Good afternoon";
}
}
else if (now.Hour >= 18 && now.Hour <= 20)
{
this.userGreeting = "Good evening";
}
else
{
this.userGreeting = "Good night";
}
}
[MessageBodyMember(Order = 1, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public String UserGreeting
{
get { return this.userGreeting; }
}
public Greeting()
{
this.SetGreeting();
}
}
}
using System;
using System.ServiceModel;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel.services.contract
{
[ServiceContract(Namespace = "http://jeanjmichel.blogspot.com/services/v0.0.1")]
public interface IGetGreeting
{
[OperationContract]
Greeting GetGreeting(Credential credential);
}
}
using System;
using System.ServiceModel;
using com.blogspot.jeanjmichel.services.contract;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel.services
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
Namespace = "http://jeanjmichel.blogspot.com/services/v0.0.1")]
public class GetGreetingService: IGetGreeting
{
public Greeting GetGreeting(Credential credential)
{
if (String.IsNullOrEmpty(credential.Token))
{
throw new FaultException("Inform the security phrase, and try again.");
}
else
{
if (credential.Token.Equals("mySeCuriTyP#ss"))
{
Greeting g = new Greeting();
return g;
}
else
{
throw new FaultException("Wrong password.");
}
}
}
}
}
When you are using Message object as a parameter, the method should return void
If you have the issue with mixed types of primitive(such as string) and MessageContract as the other type, i.e. one class as return and a string parameter, one way I solved this was switching from MessageContract to DataContract.
The other way to solve this would be to create a class to hold your primitive type as a property, so that both your return and parameter can implement MessageContract.
I ran into this error while maintaining an API in our code. The API suddenly began returning this error for all endpoints.
I had upgraded the initialization method for Ninject to move away from a method that it said was obsolete.
Obsolete method: NinjectWebServiceHostFactory (no error)
New method: NinjectServiceHostFactory (returns error)
The error went away when I reverted the change.