I'm using the latest version of ServiceStack with NuGet. I've got a basic service setup that works fine with the JsonServiceClient and is passing all of our unit tests as expected.
Unfortunately I'm also trying to support SOAP and Visual Studios "Add Service Refernece" proxy generation for interop with other groups who want to continue using that sort of framework.
What I'm running into is that our DTO's including the Response objects are not being populated into the XSD's or wsdl's that ServiceStack is generating via the metadata page. This seems very odd in conjunction with the fact that when viewing the individual SOAP Operation examples the correct Response and DTO's are shown in the generated example.
An Example Response:
Namespace Operations
<DataContract>
Public Class GetItemResponse
Implements IHasResponseStatus
<DataMember>
Public Property ResponseStatus As ResponseStatus Implements IHasResponseStatus.ResponseStatus
<DataMember>
Public Property Item As Item
End Class
End Namespace
An Example DTO:
Namespace Types
<DataContract>
Public Class Item
<DataMember>
Public Property ItemIdentifier As String
<DataMember>
Public Property ItemId As Guid?
<DataMember>
Public Property ItemName As String
<DataMember>
Public Property Description As String
<DataMember>
Public Property InstallDate As DateTime?
<DataMember>
Public Property FeatureNumber As String
<DataMember>
Public Property ModelNumber As String
End Class
End Namespace
I'm using the Assembly: ContractNamespace attribute to set the XML namespace as well.
I've downloaded the source code and done some investigation on my own. I'm not sure how recent this change is but it appears that in order for your DTO's and Response objects to be included in the wsdl you need to add a query string like "?includeAllTypes=true".
I'm also using the ServiceStack BasicAuthProvider setup which is causing AssignRoles and UnAssignRoles to be added to the Service automatically. The request and response objects for those calls are still failing to make it into the wsdl and causing "Add Service Reference" to fail. Fortunately we aren't making use of them so if I can find another configuration setting to remove them all should be working correctly.
Related
Using an example of REST api with a GET method that takes in an object query parameter.
VSCode is configured to generate XML documentation and feed it into Swagger like in here.
The result swagger page shows documentation for the respective field in the input object
But, the object data model doesn't show in the Schema section
If the [FromQuery] gets removed from the method signature, the data model gets included in the schema
But the endpoint request body is used instead of query parameter which is not the wanted behavior.
The XML file generated in both scenarios is the same
<?xml version="1.0"?>
<doc>
<assembly>
<name>DateTimeServiceAPI</name>
</assembly>
<members>
<member name="P:DateTimeServiceAPI.DTOs.GetCurrentTimeDTO.TenantId">
<summary>
indentifer of the tenant
</summary>
</member>
</members>
</doc>
Any idea why is this difference in generating the documentation? I couldn't find anything relevant while searching about this.
How can I (force) include all data models in the schema section?
Any pointers or resources are highly appreciated.
Thank you
Update:
In the RESTfull api guide here, section 7. REST Basics - URLs:
Is it against best practices to use DTOs as query parameters?
You should check your GetCurrentTimeDTO model, the properties of a DTO that's used as a parameter to a controller method should have public set, if it is internal or private Swagger won't show it.
public class MyDto
{
public Guid Id { get; internal set; } // Not shown
public DateTime Date { get; set; } //shown
}
Have you tried to explicitly include documentation in swagger?
I've got a SOAP web-service server using Apache CXF as implementation. Due to some external technical constraint I'd like to be able to rename some XML tags naming an operation parameter (which are deprecated) in the inbound SOAP request. I was reading about using Interceptors for this, but the documentation on how to setup/configure them is not very clear.
My code to publish an endpoint is the following:
Endpoint endpoint = Endpoint.create(
"http://schemas.xmlsoap.org/soap/", new MyServer());
endpoint.publish("ws/endpoint");
Ideally I'd like to add a filter only to a given endpoint (I have several of them).
Apache's documentations about interceptors are quite clear (IMO), anyway, there is a helloworld project (based on spring boot, cxf and maven) in my github profile which you can take a look for setting up interceptors (in fact it's a baisc autentication interceptor).
For setting up an interceptor (e.g InInterceptor), your class should extend AbstractPhaseInterceptor<Message> and override handleMessage(Message message) method, then in the constructor you should declare the phase in which the interceptor is going to be applied. Finally you have to instantiate it and apply in on an Endpoint.
As you said:
rename some XML tags naming an operation parameter (which are
deprecated) in the inbound SOAP request
I think the name of the operation parameter (in WSDL file) is something different from the argument of your web method. Suppose that there is method in your endpoint named addPerson:
#WebMethod
String addPerson(Person person) {
/*method logic*/
}
and Person class:
class Person {
private String firstName;
private String lastName;
private Date birthDate;
//getters and setters
}
in order to map lastName property to a different name, you have to annotate it with
#XmlElement(name = "sureName")
private String lastName;
after applying this anotation, sureName (in wsdl file) is going to be mapped to lastName.
In addition, there is #WebParam annotation which can be used for changing the name of web method arguments:
#WebMethod
String sayHello( #WebParam(name = "sureName") String lastName);
Hope it helps.
I have a Jersey controller that is returning a List<MyPojo> (it is actually returning an ArrayList. My pom includes jersey-server and so I am automatically getting jersey-media-jaxb and I have verified that my war does contain that dependency.
The endpoint is marked with:
#Produces(value={MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
When I hit it with no accept specified (or with application/json) I get back JSON with no issues. But when I specify 'accept=application/xml` I get:
MessageBodyWriter not found for media type=application/xml, type=class java.util.ArrayList, genericType=java.util.List<MyPoJo>
Not sure if it matters, but I am using Spring boot but I am not using the jersey starter due to version issues.
Update
As a note: this worked using Spring MVC and the default output was XML.
I can't copy/paste the method but here is outline
Method:
#Get
#Path("/since")
#Produces(value={MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public List<MyMetadata> since(){
return callService(paramaters);
}
// The below pre-existed me
public class MyMetadata{
private String id;
#JsonSerialize(using=DateTimeSerializer.class)
#JsonDeserialize(using=MyDateTimeDeserializer.class)
private DateTime startTime;
private List<String> ids;
private List<OtherPojo> uuids;
private SecurityPojo security;
private Set<MyTuples> ads;
}
I have a REST webservice with method custom (GET).
#GET
#Path("/custom")
public UIResponse custom(final UIParameters uiParameters){...}
As you can see this method has one argument. This is my custom object.
Object UIParameters is built from argument given as query string.
eg. http://example.com/custom?objectType=article
UIParameters object will contain one field:
UIParameters {
String objectType = "article";
}
I have tried to use InInterceptor to get this parameter from URL, build UIParameter object and set Content of message. Unfortunatelly it doesn't work.
After that I've provide MessageBodyReader for UIParameters but it still doesn't work.
What should I do to achive this goal?
Thanks
Update:
In InInterceptor I've copied query string to http headers. Now part of URL where user place parameters is accessible in my MessageBodyReader. Here I can build my object UIParameters.
Everything works fine but I don't think that this solution is the best.
Does somebody know better solution?
AnnotationQueryParam("") allows to get all the query parameters injected.
You do not need an interceptor and it is not the recommended way. See CXF documentation http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-Parameterbeans
#GET
#Path("/custom")
public UIResponse custom(#QueryParam("") UIParameters uiParameters)
class UIParameters {
String objectType;
}
If you want to build the bean yourself using the query parameters use #Context UriInfo annotation
#GET
#Path("/custom")
public UIResponse custom( #Context UriInfo uriInfo){
MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
new UIParameters().Builder()
.objectType(params.getFirst("type"))
.build();
}
Forgive me if I am just being thick but the Spyne documentation on headers seems a bit thin and the link to the sample code is broken. I think I found the sample code here but it only seems to access the headers in a listener callback function. I need access to it in the srpc method if possible.
What I would like to do is something like this (this does not work):
class MyRequest(ComplexModel):
Messages = Array(Unicode)
class MyHeader(ComplexModel):
TrackingID = ByteArray
class MySoapService(ServiceBase):
#srpc(MyRequest, _in_header=MyHeader)
def PostMessages(req, hdr):
logging.info(u'RECEIVED: {0:s}'.format(hdr.TrackingID))
If it helps, I am trying to replace a service written in .NET that just defines the message headers in the message contract like this:
[MessageContract]
public class MyRequest
{
[MessageHeader]
public Guid TrackingID { get; set; }
[MessageBodyMember]
public String[] Messages { get; set; }
}
You can't read header data from within an srpc function. #srpc is for existing functions that you don't want to touch. You should always use #rpc unless you know you need #srpc
Decorate your function using #rpc. This passes the rpc context (conventionally named ctx) as first argument to your function. Then, ctx.in_header is where you'll find the header data. You can also set ctx.out_header to alter outgoing response headers.
Also, pull requests for docs are pure gold to me :)