ServiceStack not receiving values on OnDelete - servicestack

On OnDelete of ServiceStack, it is called but the values are empty.
I tried to check the value, e.g.
ProductRequestResponse rx = Client.Send<ProductRequestResponse>(
"DELETE", "http://localhost:2012/api/product_request",
new ProductRequest { Id = 7 });
On the ServiceStack side, I only receive an Id of 0. Here's my StackService OnDelete method.
public override object OnDelete(ProductRequest request)
{
throw new Exception("Id: " + request.Id.ToString());
}
Here's my objects use for communication
public class ProductRequest
{
public int Id { get; set; }
public ProductDto ProductDto { get; set; }
}
public class ProductRequestResponse
{
public ProductDto ProductDto { get; set; }
public IEnumerable<ProductDto> ProductDtos { get; set; }
public ServiceStack.ServiceInterface.ServiceModel.ResponseStatus ResponseStatus { get; set; } //Where Exceptions get auto-serialized
}
What am I missing, why StackService is not receiving any value from OnDelete method?

Firstly, you should be using the Delete method as the Send only does POST's:
So it looks something like:
restClient.Delete<TransactionLogResponse>("/transactionlog");
The reason why Delete doesn't expect a Request DTO is because the DELETE Http verb does not accept a request body.
If you want to add paramaters you should add this on the route path or query string, e.g:
restClient.Delete<TransactionLogResponse>("/transactionlog/1?Arg1=a&Arg2=b");

Related

Autquery not including nested result when using a response DTO

Let's say you have these models:
public class Blog
{
[PrimaryKey]
[AutoIncrement]
public int Id { get; set; }
public string Url { get; set; }
public string PrivateField { get; set; }
[Reference]
public List<BlogToBlogCategory> BlogToBlogCategories { get; set; }
}
public class BlogResponse
{
public int Id { get; set; }
public string Url { get; set; }
public List<BlogToBlogCategory> BlogToBlogCategories { get; set; }
}
And this request:
public class BlogsLookUpRequest : QueryDb<Blog, BlogResponse>
{
}
The return value will have BlogToBlogCategories as null, but this request:
public class BlogsLookUpRequest : QueryDb<Blog>
{
}
Will have BlogToBlogCategories populated. I can manually create the query response like so with custom implementation:
var q = _autoQuery.CreateQuery(request, Request.GetRequestParams(), base.Request);
var results = _autoQuery.Execute(request,q, base.Request);
return new QueryResponse<ResponseBlog>()
{
Results = results.Results.ConvertTo<List<ResponseBlog>>(),
Offset = request.Skip,
Total = results.Total
};
Then it will have the nested results. If I decorate the collection with [Reference] then it is trying to find foreign key on non-existant BlogResponse table.
Why are referenced results removed when specifying a return model with AutoQuery? Is there a way to mark it up so it works?
The POCO Reference Types is used to populate Data Models not adhoc Response DTOs.
In this case it's trying to resolve references on a non-existent table, you can specify which table the DTO maps to with [Alias] attribute, e.g:
[Alias(nameof(Blog))]
public class BlogResponse
{
public int Id { get; set; }
public string Url { get; set; }
public List<BlogToBlogCategory> BlogToBlogCategories { get; set; }
}

Can AutoQuery return a single item (not list)

When I add a type to AutoQuery, with:
[Route("/templates")]
public class SearchTemplates : QueryDb<Template>
{
public int? Id { get; set; }
public string Name { get; set; }
}
then I can query this object by Id or Name (or whatever other attributes I would add, that the POCO Template has). However it always returns list of items.
It's very useful to be able to GET a single item (not a search result).
This is how I do it:
[Route("/template/{Id}","GET")]
public class SingleTemplate : IReturn<Template>
{
public int Id { get; set; }
}
public Template Get(SingleTemplate request)
{
return Db.LoadSingleById<Template>(request.Id);
}
With all the new AutoQuery and AutoCRUD, it seems to me that the "return a single item by its URL" could also be automatic?
No, All AutoQuery QueryDb<T> services return the same fixed QueryResponse Response DTO as per its Service Contract, i.e:
public abstract class QueryDb<T>
: QueryBase, IQueryDb<T>, IReturn<QueryResponse<T>> { }
public abstract class QueryDb<From, Into>
: QueryBase, IQueryDb<From, Into>, IReturn<QueryResponse<Into>> { }
public class QueryResponse<T> : IQueryResponse
{
public virtual int Offset { get; set; }
public virtual int Total { get; set; }
public virtual List<T> Results { get; set; }
public virtual Dictionary<string, string> Meta { get; set; }
public virtual ResponseStatus ResponseStatus { get; set; }
}
A single result would still populate the Results property, so the JSON wire format would look like:
{ "results":[ {/*Template*/} ] }
You could create your own Custom AutoQuery Implementation that utilizes AutoQuery's IAutoQueryDb API to return your own custom populated DTO but then your Request DTO should NOT inherit from QueryDb<T> as not returning a QueryResponse<T> would break the explicit Service contract of the Request DTO (and all clients expecting it), i.e. you would instead just create a normal ServiceStack Service returning your own custom Response Type.

PATCH in ServiceStack

I am trying to patch a object with the following code.
public object Patch(EditBlog request)
{
using (var db = _db.Open())
{
try
{
request.DateUpdated = DateTime.Now;
Db.Update<Blog>(request, x => x.Id == request.Id);
return new BlogResponse { Blog = Blog = Db.Select<Blog>(X=>X.Id == request.Id).SingleOrDefault()};
}
catch (Exception e)
{
return HttpError.Conflict("Something went wrong");
}
}
}
In Postman, I am calling the function like this "api/blog/1?=Title=Test1&Summary=Test&UserId=1".
When debugging I can see that those values has been assigned to the request.
During the Update it throws: "Cannot update identity column 'Id'"
My model looks like this
public class Blog
{
[AutoIncrement]
public int Id { get; set; }
public IUserAuth User { get; set; }
[Required]
public int UserId { get; set; }
[Required]
public string Title { get; set; }
public string Summary { get; set; }
public string CompleteText { get; set; }
[Required]
public DateTime DateAdded { get; set; }
public DateTime DateUpdated { get; set; }
}
And the EditBlog DTO looks like this:
[Route("/api/blog/{id}", "PATCH")]
public class EditBlog : IReturn<BlogResponse>
{
public int Id { get; set; }
public IUserAuth User { get; set; }
public int UserId { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public string CompleteText { get; set; }
public DateTime DateUpdated { get; set; }
}
The error message "Cannot update identity column 'Id'" does not exist anywhere in ServiceStack.OrmLite, it could be an error returned by the RDBMS when you're trying to update the Primary Key which OrmLite wouldn't do when updating a Model annotated with a Primary Key like your Blog class has with its annotated [AutoIncrement] Id Primary Key.
The error is within your Db.Up<T> method that's performing the update, which is not an OrmLite API, so it's likely your own custom extension method or an alternative library.
I would implement a PATCH Request in OrmLite with something like:
var blog = request.ConvertTo<Blog>();
blog.DateUpdated = DateTime.Now;
Db.UpdateNonDefaults(blog);
i.e. using OrmLite's UpdateNonDefaults API to only update non default fields and updating using the Blog Table POCO not the EditBlog Request DTO.
Also you should use the Single APIs when fetching a single record, e.g:
Blog = Db.SingleById<Blog>(request.Id)
or
Blog = Db.Single<Blog>(x => x.Id == request.Id)
Instead of:
Blog = Db.Select<Blog>(X=>X.Id == request.Id).SingleOrDefault()

How to get Chargify Webhook Response in .Net

I have already configure webhook url in chargify. This url is for webapi.
So i'm handling all events in webapi. But I want to know that how can we get the request parameter from chargify. If anyone have an example, would you please give me.
Below is the request from the chargify webhook's one event
you can get the below link for the webhook sending request for the events.
https://docs.chargify.com/webhooks#signup-success-payload
Please help me on this.
Thanks in Advance.
I tried the solution from above but it didn't work for me (probably because it's a 2015 solution and Chargify has made a few changes in the time).
What worked for me was:
[HttpPost]
[Route("test")]
[Consumes("application/x-www-form-urlencoded")]
public ActionResult Test([FromForm] RequestObject request)
If we will use RequestObject with ModelBinding, we have to create the data structure of the objects and variables we want to use.
For instance, for the signup_success event, the data structure for the objects Product, Customer and Customer Reference will be:
public class RequestObject
{
public string id { get; set; }
public Payload payload { get; set; }
}
public class Payload
{
public Subscription subscription { get; set; }
}
public class Subscription
{
public long id { get; set; }
public Product product { get; set; }
public Customer customer { get; set; }
}
public class Product
{
public long id { get; set; }
}
public class Customer
{
public long id { get; set; }
public string reference { get; set; }
}
Since it's submitted to the webhook url as form-parameters, so in MVC your signature would look similar to the following:
public ActionResult ReceiveWebhook(FormCollection webhookPayload, string signature_hmac_sha_256)
The parameter signature_hmac_sha_256 is included in the query string, so it's passed here.
You could then run different logic by using the event:
var eventName = webhookPayload["event"];

Unexpected results returning a custom AuthenticateResponse in the new version of ServiceStack

I'm having an issue returning a custom AutenticateResponse in the new version of ServiceStack. This code worked in the previous version of ServiceStack, but after the upgrade it is no longer functioning as expected.
The AuthenticateResponse
public class CustomAuthResponse : AuthenticateResponse
{
public List<CustomCompanyDTO> Companies { get; set; }
public List<string> Roles { get; set; }
public List<string> Permissions { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
}
The Service
public class CurrentUserService : AppServiceBase
{
public object Any(CurrentUser cu)
{
CustomAuthResponse response = new CustomAuthResponse();
response.DisplayName = UserSession.DisplayName;
response.Email = UserSession.Email;
response.Companies = UserSession.Companies;
response.UserName = UserSession.UserName;
response.Roles = UserSession.Roles;
response.Permissions = UserSession.Permissions;
return response;
}
}
In v3 I can call the CurrentUserService and it returns all the data as expected. In v4 when I call CurrentUserService none of the custom fields are included in the response.
I can work around this particular call by changing the code as follows:
public class CurrentUserService : AppServiceBase
{
public object Any(CurrentUser cu)
{
CustomAuthResponse response = new CustomAuthResponse();
var x = new
{
DisplayName = UserSession.DisplayName,
Email = UserSession.Email,
Companies = UserSession.Companies,
UserName = UserSession.UserName,
Roles = UserSession.Roles,
Permissions = UserSession.Permissions,
};
return x;
}
}
The above code works as expected. I can certainly change my code to work this way, I'm mostly wondering what has changed as I'm curious if it will impact my code in other places. I'm seeing the same issue when trying to return ny CustomAuthResponse from the Authenticate call my custom CredentialsAuthProvider.
The issue is likely that DataContract attributes are now inherited and if a DTO is marked as a [DataContract] it's opt-in and only the properties marked with DataMember are serialized.
As AuthenticateResponse is a DataContract, if you want to re-use the DTO you should mark the properties you want serialized with a [DataMember] attribute, e.g:
[DataContract]
public class CustomAuthResponse : AuthenticateResponse
{
[DataMember]
public List<CustomCompanyDTO> Companies { get; set; }
[DataMember]
public List<string> Roles { get; set; }
[DataMember]
public List<string> Permissions { get; set; }
[DataMember]
public string DisplayName { get; set; }
[DataMember]
public string Email { get; set; }
}

Resources