How to implement Delete service call using ServiceStack - c#

I have couple of questions related to REST service implementation using ServiceStack.
For GET operation, I define my request DTO as below :
[Route("/Customer/{ID}", Verbs = "GET")]
public class GetCustomer : IReturn<GetCustomerResponse>
{
....
....
}
Here "GetCustomer" is request DTO and "GetCustomerResponse" is response DTO. But for PUT/POST/DELETE operation, I just need to know whether operation got committed successfully or not and if 'not' then what is the exception. So what should be my request dto definition for POST/PUT/DELETE? Should it use IReturnVoid as shown below?
[Route("/Customer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturnVoid
{
....
....
}
If I have to use IReturnVoid then how I can retrieve any exception information that might occur on committing my operation?
In the error handling document for service stack it is written and I quote below
Error Response Types
The Error Response that gets returned when an Exception is thrown
varies on whether a conventionally-named {RequestDto}Response DTO
exists or not.
If it exists:
The {RequestDto}Response is returned, regardless of the service
method's response type. If the {RequestDto}Response DTO has a
ResponseStatus property, it is populated otherwise no ResponseStatus
will be returned. (If you have decorated the {ResponseDto}Response
class and properties with [DataContract]/[DataMember] attributes, then
ResponseStatus also needs to be decorated, to get populated).
Otherwise, if it doesn't:
A generic ErrorResponse gets returned with a populated ResponseStatus
property.
The Service Clients transparently handles the different Error Response
types, and for schema-less formats like JSON/JSV/etc there's no actual
visible difference between returning a ResponseStatus in a custom or
generic ErrorResponse - as they both output the same response on the
wire.
What I'm not getting from above is what should be the return type for my Delete method in my service implementation? How I can implement my delete method without defining delete response DTO but yet I'm able to retrieve 'ErrorResponse' n exception info?
Is it possible to define route with "DELETE" verb? I have following implementation.
Route:
[Route("/DeleteCustomer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturn<DeleteCustomerResponse>
{
public int ID { get; set; }
}
Method implementation:
public DeleteContactResponse Delete(DeleteContact request)
{
.....
}
But whenever I call this delete using my client, I always get "NotFound" exception. I tried different clients but with all I get 404 error.
One of the reference link available alongwith Servicestack document reuses the "GET" and "DELETE" verb together.
Another link suggests not all browsers support delete operation.
So I wonder how Delete operation should be implemented?

See this earlier answer for details on how to design a REST-ful API with ServiceStack.
The CustomerRestExample contains a complete stand-alone example of a Customer REST ServiceStack Service:
Customer Service Definition
Here's an example of the custom Routes and Request DTO's of what a typical Customer REST Service could look like:
[Route("/customers", "GET")]
public class GetCustomers : IReturn<GetCustomersResponse> {}
public class GetCustomersResponse
{
public List<Customer> Results { get; set; }
}
[Route("/customers/{Id}", "GET")]
public class GetCustomer : IReturn<Customer>
{
public int Id { get; set; }
}
[Route("/customers", "POST")]
public class CreateCustomer : IReturn<Customer>
{
public string Name { get; set; }
}
[Route("/customers/{Id}", "PUT")]
public class UpdateCustomer : IReturn<Customer>
{
public int Id { get; set; }
public string Name { get; set; }
}
[Route("/customers/{Id}", "DELETE")]
public class DeleteCustomer : IReturnVoid
{
public int Id { get; set; }
}
OrmLite POCO Model:
public class Customer
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
}
Essentially the Custom Routes identify the Resource whilst the HTTP VERB indicates the operation on that Resource. Looking at the HTTP Requests makes this a little clearer:
GET /customers -> return all Customers
POST /customers -> Create a new Customer
GET /customers/1 -> return Customer 1
PUT /customers/1 -> Update Customer 1
DELETE /customers/1 -> Delete Customer 1
Customer Service Implementation
With the above DTO's definitions in-place, we can now implement this Customer REST Service by adding an implementation for each Request DTO - in this example using OrmLite:
public class CustomerService : Service
{
public object Get(GetCustomers request)
{
return new GetCustomersResponse { Results = Db.Select<Customer>() };
}
public object Get(GetCustomer request)
{
return Db.SingleById<Customer>(request.Id);
}
public object Post(CreateCustomer request)
{
var customer = new Customer { Name = request.Name };
Db.Save(customer);
return customer;
}
public object Put(UpdateCustomer request)
{
var customer = Db.SingleById<Customer>(request.Id);
if (customer == null)
throw HttpError.NotFound("Customer '{0}' does not exist".Fmt(request.Id));
customer.Name = request.Name;
Db.Update(customer);
return customer;
}
public void Delete(DeleteCustomer request)
{
Db.DeleteById<Customer>(request.Id);
}
}
Customer Usage Example
With the above Customer REST Service implementation, we can re-use the Request DTO's with ServiceStack's .NET Service Clients to provide an end-to-end Typed API without code-gen, i.e:
var client = new JsonServiceClient(BaseUri);
//GET /customers
var all = client.Get(new GetCustomers()); // Count = 0
//POST /customers
var customer = client.Post(new CreateCustomer { Name = "Foo" });
//GET /customer/1
customer = client.Get(new GetCustomer { Id = customer.Id }); // Name = Foo
//GET /customers
all = client.Get(new GetCustomers()); // Count = 1
//PUT /customers/1
customer = client.Put(
new UpdateCustomer { Id = customer.Id, Name = "Bar" }); // Name = Bar
//DELETE /customers/1
client.Delete(new DeleteCustomer { Id = customer.Id });
//GET /customers
all = client.Get(new GetCustomers()); // Count = 0
The comments above include the HTTP Operations performed in each Service Client example.

I got the fix for my 2nd question from following two links :
1. Link1
2. Link2
I don't fully understand this fix but doing above changes worked for me and now I can call Delete function from any clients.
For 1st question, pls refer #mythz 's reply below in detail.

Related

Creating a generic payments library

I am trying to create Payment Gateway abstraction, for one of my projects using Asp.Net Core, so that clients can integrate their payment gateways, by creating derived libraries. My application will load the derived libraries and call the methods.
Below is an interface that all payment gateways must implement. This lies in the Core library, let's call it PaymentGateway.Core.dll. This library is part of the main application.
namespace PaymentGateway.Core
{
public interface IPaymentGateway
{
string Name { get; }
// The purpose of this function is to transform the order details into an object,
// as expected by the underlying gateway's apis
object CreatePaymentRequest(Order request);
// The purpose of this function is to transform the payment response object,
// received from the payment gateway api,
// into an application entity that represents this payment.
Payment ProcessPaymentResponse(object response);
}
// Order for which the payment to be collected. This entity is stored in DB
public class Order
{
string UserId { get; set; }
string ProductId { get; set; }
double OrderTotal { get; set; }
}
// A payment attempted for an Order. This entity is stored in DB
public class Payment
{
Order Order { get; set; }
string PaymentGateway { get; set; }
double Amount { get; set; }
PaymentStatus Status { get; set; } // Failed, User Aborted, Success
}
}
Below is an example of PayPal integration library, let's call it PaymentGateway.PayPal.dll. This library references the core library and implements the PaymentGateway interface.
namespace PaymentGateway.PayPal
{
class PayPal : IPaymentGateway
{
public string Name { get => "PayPal"; }
public object CreatePaymentRequest(Order request)
{
:
:
}
public Payment ProcessPaymentResponse(object response)
{
:
:
}
}
}
The process flow in the core library to execute a payment would be like :
The buyer clicks on the PayPal button on the webpage.
The core application then initializes the PayPal object.
The core application then calls the CreatePaymentrequest() function with the order details. The function will transform the order details into PayPal Payment Request format.
The returned data is passed to PayPal apis to initiate a transaction.
After PayPal api finishes, it returns the response in a its defined format.
The response from PayPal api is passed to the server, which calls ProcessPaymentResponse() on the PayPal object. This function transform the response into Payment object.
The problem i have is that the application ( Core ) doesn't understand the return type of CreatePaymentRequest(), as it is depends on the called gateway. Similarly, for ProcessPaymentResponse() the argument type is gateway specific and the type will be defined in the gateway library.
For now i am forced to use System.Object. Is there any better solution to the problem ?
public interface IPaymentGateway<T> where T : class
{
string Name { get; }
T CreatePaymentRequest(PaymentRequest request);
PaymentResponse ProcessPaymentResponse(T response);
}
public class PayPal<T> : IPaymentGateway<T> where T : class
{
public string Name { get; }
public T CreatePaymentRequest(PaymentRequest request)
{
throw new NotImplementedException();
}
public PaymentResponse ProcessPaymentResponse(T response)
{
throw new NotImplementedException();
}
}
public class Example
{
public void ExampleMethod()
{
IPaymentGateway<Foo> paypal = new PayPal<Foo>();
var name = paypal.Name;
Foo paymentRequest = paypal.CreatePaymentRequest(new PaymentRequest());
var paymentResponse = paypal.ProcessPaymentResponse(new Foo());
}
}
public class Foo
{
}
public class PaymentResponse
{
}
public class PaymentRequest
{
}
Instead of returning an object why not make it generic and have them pass in the type?

Receiving 500 internal server error even though I receive data from LINQ

StackOverflow.
The issue I am having today is when I send a get request to localhost:xxxxx trying to obtain a singular food item by ID, I receive a 500 internal server error.
What I do not understand about this is, I went through the code in debugging and it shows that it finds the item from my database with all the information it needs, but when it is sending it in a "OK(food)", I receive a 500 internal service error even though it has the information.
I am pretty new to web api, so some explanation would be appreciated. I am using Visual Studio 2015, Entity Frame Work 6, and a SQL Management Server DB.
I am sorry for posting links, it says I need 10 reputation to post images
protected void Page_Load(object sender, EventArgs e)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:63591/");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("api/foods/" + Request.QueryString["ID"]).Result;
if (response.IsSuccessStatusCode)
{
string foodstring = response.Content.ReadAsStringAsync().Result;
Food editFood = JsonConvert.DeserializeObject<Food>(foodstring);
EditFoodName.Text = editFood.FoodName;
EditCalories.Text = editFood.Calories.ToString();
EditNotes.Text = editFood.Notes;
}
}
[ResponseType(typeof(Food))]
public IHttpActionResult GetFood(int id)
{
Food food = db.Foods.Find(id);
if (food == null)
{
return NotFound();
}
return Ok(food);
}
public partial class Food
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Food()
{
this.MealFoods = new HashSet<MealFood>();
}
public int FoodID { get; set; }
public string FoodName { get; set; }
public int Calories { get; set; }
public string Notes { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MealFood> MealFoods { get; set; }
}
https://i.imgur.com/8h6EaZM.png
https://i.imgur.com/YkD8Ijp.png
In the action GetFood you specified that the return type is Food. By default the EntityFramework generate proxy objects around your entities for lazy-loading.
Meaning that the line:
Food food = db.Foods.Find(id);
Will not return a Food object, but a dynamic subclass of food. This can also be seen in the error you posted in the comments, stating that the action is not expecting type Food_31C9E7DC... to be returned.
There are 3 ways to fix this:
Simply disable proxy generation in your EntityContext,
Remove virtual properties (lazy-loading properties) on your entity (EF will skip proxy generation if its not needed),
Map your EntityObject into a DataContract object and return it.
See here for more info on proxies.
Instead work directly with db.Foods, it's better to create your own public object and manage your query with Linq or if you persist to work directly with the object created by EntityFramework you must disable lazy-loading and proxy generation.
Using your own implementation, the method should be like this:
[ResponseType(typeof(PseudoFood))]
public IHttpActionResult GetFood(int id)
{
//Food food = db.Foods.Find(id);
PseudoFood food = (from a in db.Foods
where a.FoodID == id
select new PseudoFood()
{
FoodName = a.FoodName,
FoodID = a.FoodID,
Calories = a.Calories,
Notes = a.Notes
}).FirstOrDefault();
if (food == null)
{
return NotFound();
}
return Ok(food);
}
Attention for the [ResponseType(typeof(PseudoFood))], that use PseudoFood instead Food.

Exception when returning list of objects with servicestack

I am attempting to get ServiceStack to return a list of objects to a C# client, but I keep getting this exception:
"... System.Runtime.Serialization.SerializationException: Type definitions should start with a '{' ...."
The model I am trying to return:
public class ServiceCallModel
{
public ServiceCallModel()
{
call_uid = 0;
}
public ServiceCallModel(int callUid)
{
this.call_uid = callUid;
}
public int call_uid { get; set; }
public int store_uid { get; set; }
...... <many more properties> ......
public bool cap_expense { get; set; }
public bool is_new { get; set; }
// An array of properties to exclude from property building
public string[] excludedProperties = { "" };
}
The response:
public class ServiceCallResponse
{
public List<ServiceCallModel> Result { get; set; }
public ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized
}
And the service:
public class ServiceCallsService : Service
{
// An instance of model factory
ModelFactory MyModelFactory = new ModelFactory();
public object Any(ServiceCallModel request)
{
if (request.call_uid != 0)
{
return MyModelFactory.GetServiceCalls(request.call_uid);
} else {
return MyModelFactory.GetServiceCalls() ;
}
}
}
The client accesses the service with:
JsonServiceClient client = new ServiceStack.ServiceClient.Web.JsonServiceClient("http://172.16.0.15/");
client.SetCredentials("user", "1234");
client.AlwaysSendBasicAuthHeader = true;
ServiceCallResponse response = client.Get<ServiceCallResponse>("/sc");
The "model factory" class is a DB access class which returns a list. Everything seems to work just fine when I access the service through a web browser. The JSON returned from the service starts:
"[{"call_uid":70...."
And ends with:
"....false,"is_new":true}]"
My question is, what here might be causing serialization/deserialization to fail?
Solution
Thanks to the answer from mythz, I was able to figure out what I was doing wrong. My misunderstanding was in exactly how many DTO types there are and exactly what they do. In my mind I had them sort of merged together in some incorrect way. So now as I understand it:
Object to return (In my case, called "ServiceCallModel": The actual class you wish the client to have once ServiceStack has done its job. In my case, a ServiceCallModel is a key class in my program which many other classes consume and create.
Request DTO: This is what the client sends to the server and contains anything related to making a request. Variables, etc.
Response DTO: The response that the server sends back to the requesting client. This contains a single data object (ServiceCallModel), or in my case... a list of ServiceCallModel.
Further, exactly as Mythz said, I now understand the reason for adding "IReturn" to the request DTO is so the client will know precisely what the server will send back to it. In my case I am using the list of ServiceCallModel as the data source for a ListView in Android. So its nice to be able to tell a ListViewAdapter that "response.Result" is in fact already a useful list.
Thanks Mythz for your help.
This error:
Type definitions should start with a '{'
Happens when the shape of the JSON doesn't match what it's expecting, which for this example:
ServiceCallResponse response = client.Get<ServiceCallResponse>("/sc");
The client is expecting the Service to return a ServiceCallResponse, but it's not clear from the info provided that this is happening - though the error is suggesting it's not.
Add Type Safety
Although it doesn't change the behavior, if you specify types in your services you can assert that it returns the expected type, e.g Change object to ServiceCallResponse, e.g:
public ServiceCallResponse Any(ServiceCallModel request)
{
...
}
To save clients guessing what a service returns, you can just specify it on the Request DTO with:
public class ServiceCallModel : IReturn<ServiceCallResponse>
{
...
}
This lets your clients have a more succinct and typed API, e.g:
ServiceCallResponse response = client.Get(new ServiceCallModel());
instead of:
ServiceCallResponse response = client.Get<ServiceCallResponse>("/sc");
See the New API and C# Clients docs for more info.

ServiceStack: JsonServiceClient usage without IReturn in DTO

What I would like to do is the following:
var client = new JsonServiceClient(ServiceUrl);
var request = new FooQuery {Id = 1};
IEnumerable<Project> response = client.Get(request);
However, my FooQuery doesn't implement any IReturn, and I'd like it not to (it's in a library without ServiceStack references). Here's my service side:
Library of business objects:
public class ProjectQuery
{
public int Id { get; set; }
}
AppHost:
Routes.Add<ProjectQuery>("/project", "GET");
Service:
public object Get(Foo request)
{
// do stuff.
}
Is there some nice, clean way to create the JsonServiceClient without using the IReturn interface on my business object?
Looks like there's no way not to use IReturn if you don't want to provide a URL to the JsonServiceClient Get() requests. Just decided to create another set of DTOs in my ServiceStack implementation, that are essentially mirrors of the real DTOs in another library. Then when a request comes in to my SS DTO, I create the other library's DTO, set each property, and pass it along.
Not pretty, but that's the best I could find so far.
I had the same problem using IReturn and Routes, as I wanted to use the DTOs
in assemblies with business logic, without ServiceStack references.
It worked for me, using in the Client Model
public class TestRequest
{
public int vendorId {get; set; }
public string barcode {get; set; }
public string username { get; set; }
public string password { get; set; }
}
then in the AppHost
Routes.Add<TestRequest( "/TestAPI/Reservation/{vendorId}/{barcode}"," GET,OPTIONS")
.Add<TestRequest>("/TestAPI/Reservation", "POST, OPTIONS")
and the call for JsonServiceClient with POST
request.vendorId=12344;
request.barcode="AAS1223";
TestResponse response = client.Post<TestResponse>(server_ip + "/TestAPI/Reservation", request);
OR with GET
TestResponse response = client.Get<TestResponse>(server_ip + "/TestAPI/Reservation/12344/AAS1223?username=John&password=99");
Then in the service Get or Post functions
public TestResponse Get(TestRequest request)
{
// request members hold the values of the url.
return DoBusinessLayerWork(request);
}
Using the Send() method from the JsonServiceClient type is the way to go about doing this.

WCF Guid DataMember not Serialized properly

I have a WCF service that passes back and forth the following DataContracts:
[DataContract]
public class RequestWrapper
{
[DataMember]
public FooDataContract FooDataContract;
}
[DataContract]
public class ResponseWrapper
{
[DataMember]
public FooDataContract FooDataContract;
}
[DataContract]
public class FooDataContract
{
public FooDataContract(string data, Guid id)
{
Data = data;
ID = id;
}
[DataMember]
public string Data { get; set; }
[DataMember]
public Guid ID { get; set; }
}
It's called via a proxy class like this:
void CallService(string data)
{
var id = Guid.NewGuid();
var response = proxy.CallService(new RequestWrapper
{
new FooDataContract(data, id);
});
}
This is then passed (over the service) to the database via a repository using EF:
public void RepoMethod(FooDataContract foo)
{
var guid = foo.ID; // - Breakpoint here shows all zeros!
efContext.DoSomething(foo.Data, foo.ID);
}
Here's the service call:
public ResponseWrapper CallService(RequestWrapper request)
{
var foo = request.FooDataContract;
repository.RepoMethod(foo);
var response = new ResponseWrapper{ FooDataContract = foo };
return response;
}
Here's the proxy:
public class Proxy : IMyService
{
static readonly ChannelFactory<IMyService> channelFactory =
new ChannelFactory<IMyService>("IMyService");
ResponseWrapper CallService(RequestWrapper request)
{
return channelFactory.UseService(s => s.CallService(request));
}
}
internal static class UseServiceFunction
{
internal static R UseService<T, R>
(this ChannelFactory<T> channelFactory, Func<T, R> useService)
{
var service = channelFactory.CreateChannel();
try
{
R response = useService(service);
return response;
}
finally
{
var channel = service as ICommunicationObject;
try
{
if (channel.State != CommunicationState.Faulted) channel.Close();
}
catch { channel.Abort(); }
}
}
}
I've put a watch on the Guid in the VS debugger. When the service is called from a client web application, the generated Guid is a valid Guid of seemingly random hex characters. Great, that's working.
But when the data is serialized, goes over the wire, and comes out the other side (in my repository), the Guid is all zeros!
I've double, triple checked that the Guid is indeed marked with the [DataMember] attribute. I'm wondering if the extra layer of DataContract (how a FooDataContract is wrapped with the RequestWrapper data contract) is causing a serialization issue?
I think your problem here is that the constructor you've made in your DataContract class doesn't get passed to the proxy on the client side. WSDL won't know anything about this. Think of your data contracts as just a place to stick data with no other functionality. To confirm, you can look in the reference.cs class that got generated in the client when you added the service reference.
I'd suggest re-writing the code so that you explicitly set each of the values in your data contract rather than relying on the constructor.
You can also write a hand coded proxy that has whatever behavior you want and then share that file with the client. That would work, but then you'll be more tightly coupling your client to your service.
Turns out, my translation layer wasn't updated to convert between the DTOs! Whooooops!

Categories