-
Notifications
You must be signed in to change notification settings - Fork 0
SOAP support
If you want to support SOAP, you have to note some important things, because of the lack of other HTTP verbs except for POST
in SOAP.
If you only want to support REST, you can take the easy route:
//Request DTO
public class Customers {...}
public class CustomersService : Service
{
//Get customers
public object Get(Customers request) {...}
//Add customer
public object Post(Customers request) {...}
//Update customer
public object Put(Customers request) {...}
//Delete customer
public object Delete(Customers request) {...}
}
//In the AppHost's configure method
Routes.Add<Customers>("/customers")
.Add<Customers>("/customers/{Id}");
SOAP only supports POST
requests. But the REST example makes use of GET
, DELETE
(...) requests, which aren't available with SOAP. So if you want to support SOAP and REST, you need to create one service for each operation:
//Request DTO - Add DataMember attribute for all properties.
[DataContract]
public class GetCustomers {...}
[DataContract]
public class UpdateCustomer {...}
[DataContract]
public class AddCustomer {...}
[DataContract]
public class DeleteCustomer {...}
//Service
public class CustomersService : Service
{
public object Any(GetCustomers request){...}
public object Any(AddCustomer request){...}
public object Any(UpdateCustomer request){...}
public object Post(UpdateCustomer request){...}
public object Any(DeleteCustomer request){...}
}
The method Run
gets executed on each HTTP verb and on each endpoint. Make sure that DTO objects have [DataContract]
attribute (and [DataMember]
attribute for object properties) otherwise the scheme won't be generated correctly.
Note: SOAP uses the HTTP POST verb. Therefore, each service must have
Any()
orPost()
methods to support SOAP.
Now that you have multiple web services you can register them all together to expose them as a single REST-ful resource (as seen with the REST service above):
//In the AppHost's configure method
Routes.Add<GetCustomers>("/customers", "GET")
.Add<GetCustomers>("/customers/{Id}", "GET")
.Add<AddCustomer>("/customers", "POST")
.Add<UpdateCustomer>("/customers/{Id}", "PUT")
.Add<DeleteCustomer>("/customers/{Id}", "DELETE")
Note: Don't forget to specify the HTTP verb filters!
Now this webservice supports REST and SOAP and has the same REST endpoint as the above service, they equal 1:1.
IRequiresSoapMessage
works similar to IRequiresRequestStream interface to tell ServiceStack to skip de-serialization of the request and instead pass the raw WCF Message to the Service instead for manual processing, e.g:
public class RawWcfMessage : IRequiresSoapMessage {
public Message Message { get; set; }
}
public object Post(RawWcfMessage request) {
request.Message... //Raw WCF SOAP Message
}
SOAP expects that each request always returns the same response DTO. So you need to follow the response DTO naming convention, otherwise ServiceStack won't be able to generate the WSDLs and the SOAP endpoint won't work.
Naming convention: {Request DTO Name} + Response
Example: Request DTO:
DeleteCustomer
--> Response DTO:DeleteCustomerResponse
.
If you would leave the services as they are, the REST endpoint wouldn't exist. So you need to hook them all up on the same URL like that:
The other requirement with SOAP endpoints is for all DTO types to share the same single namespace which should match the Config.WsdlServiceNamespace
if you want to change it from the default namespace: http://schemas.servicestack.net/types
. E.g. You can change the default WSDL Namespace in your AppConfig with:
SetConfig(new EndpointHostConfig {
WsdlServiceNamespace = "http://my.new.namespace.com/types",
});
This can easily be done by using the [assembly:ContractNamespace]
attribute usually defined in the DTO project's AssemblyInfo.cs file, here is how this is done in the ServiceStack.Examples project:
[assembly: ContractNamespace("http://schemas.servicestack.net/types",
ClrNamespace = "ServiceStack.Examples.ServiceModel.Operations")]
[assembly: ContractNamespace("http://schemas.servicestack.net/types",
ClrNamespace = "ServiceStack.Examples.ServiceModel.Types")]
Since VS.NET's Add Service Reference
is optimized for consuming .asmx or WCF RPC method calls it doesn't properly support multiple return values (e.g. when you also want a ResponseStatus property) where it will generate an ugly proxy API complete with out parameters.
If you want to ensure a pretty proxy is generated you should only have 1 first-level property which contains all the data you want to return.
One way around it is to share your services DTO's and use any of the typed Generic Service Clients that are in-built into ServiceStack. Alternatively you can use the XSD.exe
command-line utility to generate your types on the client and use those in the typed Service Clients.
- Why ServiceStack?
- What is a message based web service?
- Advantages of message based web services
- Why remote services should use separate DTOs
- Getting Started
- Reference
- Clients
- Formats
- View Engines 4. Razor & Markdown Razor
- Hosts
- Advanced
- Configuration options
- Access HTTP specific features in services
- Logging
- Serialization/deserialization
- Request/response filters
- Filter attributes
- Concurrency Model
- Built-in caching options
- Built-in profiling
- Messaging and Redis
- Form Hijacking Prevention
- Auto-Mapping
- HTTP Utils
- Virtual File System
- Config API
- Physical Project Structure
- Modularizing Services
- Plugins
- Tests
- Other Languages
- Use Cases
- Performance
- How To
- Future