consume JSON from webhook in C# - c#

Hi I'm looking to create a simple webhook receiver and dump the data into a table.
This is for receiving SMS using Zipwhip. Zipwhip will send a post with JSON.
Need to receive the JSON and process.
What is a simple way to accomplish this.
Thanks in advance.

In ServiceStack your callback would just need to match the shape of your Response DTO, e.g:
[Route("/path/to/callback")]
public class CorpNotes
{
public int Departments { get; set; }
public string Note { get; set; }
public DateTime WeekEnding { get; set; }
}
// Example of OrmLite POCO Data Model
public class MyTable {}
public class MyServices : Service
{
public object Any(CorpNotes request)
{
//...
Db.Insert(request.ConvertTo<MyTable>());
}
}
Example uses Auto Mapping Utils to populate your OrmLite POCO datamodel, you may want to do additional processing before saving the data model.
If the callback can send arbitrary JSON Responses in the payload you can use an object property to accept arbitrary JSON however we'd recommend using Typed DTOs wherever possible.

This can be what the receiving method in your controller can look like on the receiving side. Make sure that your receiving and sending json object match.
[HttpPost]
[Route("Edit")]
public JsonResult Edit([FromBody] CorpNotes newMessage)
{return Json(TotalWeekNoteSearch);}
public class CorpNotes
{
public int Departments { get; set; }
public string Note { get; set; }
public DateTime WeekEnding { get; set; }
}
I am actually working on a .net project receiving Json from a Angular front end, so this should be the same concept. Also make sure that what you are receiving is truly a workable object such as.
{Departments: 4, Note: "This is notes 2020Q1W13", WeekEnding: "2020-01-25T00:00:00"}
Also try looking into this example which would be helpful in regards to webhooks.
public class MyWebHookHandler : WebHookHandler
{
public MyWebHookHandler()
{
this.Receiver = "custom";
}
public override Task ExecuteAsync(string generator, WebHookHandlerContext context)
{
CustomNotifications notifications = context.GetDataOrDefault<CustomNotifications>();
foreach (var notification in notifications.Notifications)
{
...
}
return Task.FromResult(true);
}
}
The type of the data is typically JSON or HTML form data, but it is possible to cast to a more specific type if desired.

Related

Using a REST Api, how to include "any kind of json" in my typed request model?

I am using .NET Framework and ASP.NET Core to create a REST web Api.
This web api has a call that gets a request model to save data and some call that later retrieves the data.
Most of the data is structured information I need in the backend and it is saved into different fields and tables in the database. On retrieval it is loaded from those tables and returned.
This all works.
However, I now have a requirement where the caller wants to save and later retrieve arbitrary data (lets just say a random json) as one of those fields. I can save and load json from the database that is not a problem, my problem is to build the web api model for my request.
[HttpPost]
public IActionResult Save([FromBody] ApiCallRequestModel request)
{
// ...
}
public sealed class ApiCallRequestModel
{
// structured, well known information
public int? MaybeSomeNumber { get; set; }
[Required]
public string SomeText { get; set; }
[Required]
public SubModel SomeData { get; set; }
// one field of unknown json data
public ??? CustomData { get; set; }
}
I could think of dynamic or maybe even ExpandoObject or JObject to try and I might, but I would like a solution that works because it's best practice, not just because I tried and it didn't fail today with my simple tests.
If everything else fails, I could just make the field a string and tell the client to put serialized json into it. But that's a workaround I would see as a last resort if this question yields no answers.
It has proven to be extremly hard to google this topic, since all words I would use lead me to pages explaining Json serialization of my request model itself. I know how that works and it's not a problem. The mix of structured data and free json is what I cannot find out from a somewhat authorative source.
So what type would you use here, what is the best practice for receiving arbitrary json in one property of your model?
So to sum this up, as suggested I used a JToken from the Json.NET nuget package, since I already had that package in my project.
[HttpPost]
public IActionResult Save([FromBody] ApiCallRequestModel request)
{
// ...
}
public sealed class ApiCallRequestModel
{
// structured, well known information
public int? MaybeSomeNumber { get; set; }
[Required]
public string SomeText { get; set; }
[Required]
public SubModel SomeData { get; set; }
// one field of unknown json data
public JToken CustomData { get; set; }
}
Works like a charm.

Dynamically change a type with C#

I am very new to C# and ServiceStack and I am working on a small project that consists on calling a third party API and loading the data I get back from the API into a relational database via ServiceStack's ORMLite.
The idea is to have each endpoint of the API have a reusable model that determines how it should be received in the API's response, and how it should be inserted into the database.
So I have something like the following:
[Route("/api/{ApiEndpoint}", "POST")]
public class ApiRequest : IReturn<ApiResponse>
{
public Int32 OrderId { get; set; }
public DateTime PurchaseDate { get; set; }
public String ApiEndpoint { get; set; }
}
public class ApiResponse
{
public Endpoint1[] Data { get; set; }
public String ErrorCode { get; set; }
public Int32 ErrorNumber { get; set; }
public String ErrorDesc { get; set; }
}
public class Endpoint1
{
[AutoIncrement]
public Int32 Id { get; set; }
[CustomField("DATETIME2(7)")]
public String PurchaseDate { get; set; }
[CustomField("NVARCHAR(50)")]
public String Customer { get; set; }
[CustomField("NVARCHAR(20)")]
public String PhoneNumber { get; set; }
public Int32 Amount { get; set; }
}
My first class represents the API's request with its route, the second class represents the API's response. The API's response is the same for all endpoints, but the only thing that varies is the structure of the Data field that comes back from that endpoint. I've defined the structure of one of my endpoints in my Endpoint1 class, and I am using it in my API's response class. As you can see, I am also defining a few attributes on my Endpoint1 class to help the ORM make better decisions later when inserting the data.
Ok, so the issue is that I have about 15 endpoints and I don't want to create 15 ApiResponse classes when I know the only thing that changes is that first Data field in the class.
So I made something like this:
public class DataModels
{
public Type getModel(String endpoint)
{
Dictionary<String, Type> models = new Dictionary<String, Type>();
models.Add("Endpoint1", typeof(Endpoint1));
// models.Add("Endpoint2", typeof(Endpoint2));
// models.Add("Endpoint3", typeof(Endpoint3));
// and so forth...
return models[endpoint];
}
}
I would like for getModel() to be called when the request is made so that I can pass in the ApiEndpoint field in the ApiRequest class and store the type that I want my Data field to have so that I can dynamically change it in my ApiResponse class.
In addition, there is the ORM part where I iterate over every endpoint and create a different table using the model/type of each endpoint. Something like this:
endpoints.ForEach(
(endpoint) =>
{
db.CreateTableIfNotExists<Endpoint1>();
// inserting data, doing other work etc
}
);
But again, I'd like to be able to call getModel() in here and with that define the model of the specific endpoint I am iterating on.
I've attempted calling getModel() on both places but I always get errors back like cannot use variable as a typeand others... so I am definitely doing something wrong.
Feel free to suggest a different approach to getModel(). This is just what I came up with but I might be ignoring a much simpler approach.
When I DID understand you correctly, you have different API-Calls which all return the same object. The only difference is, that the field "Data" can have different types.
Then you can simply change the type of data to object:
public object Data { get; set; }
And later simply cast this to the required object:
var data1=(Endpoint1[]) response.Data;
You're going to have a very tough time trying to dynamically create .NET types dynamically which requires advanced usage of Reflection.Emit. It's self-defeating trying to dynamically create Request DTOs with ServiceStack since the client and metadata services needs the concrete Types to be able to call the Service with a Typed API.
I can't really follow your example but my initial approach would be whether you can use a single Service (i.e. instead of trying to dynamically create multiple of them). Likewise with OrmLite if the Schema of the POCOs is the same, it sounds like you would be able to flatten your DataModel and use a single database table.
AutoQuery is an example of a feature which dynamically creates Service Implementations from just a concrete Request DTO, which is effectively the minimum Type you need.
So whilst it's highly recommended to have explict DTOs for each Service you can use inheritance to reuse the common properties, e.g:
[Route("/api/{ApiEndpoint}/1", "POST")]
public ApiRequest1 : ApiRequestBase<Endpoint1> {}
[Route("/api/{ApiEndpoint}/2", "POST")]
public ApiRequest2 : ApiRequestBase<Endpoint1> {}
public abstract class ApiRequestBase<T> : IReturn<ApiResponse<T>>
{
public int OrderId { get; set; }
public DateTime PurchaseDate { get; set; }
public string ApiEndpoint { get; set; }
}
And your Services can return the same generic Response DTO:
public class ApiResponse<T>
{
public T[] Data { get; set; }
public String ErrorCode { get; set; }
public Int32 ErrorNumber { get; set; }
public String ErrorDesc { get; set; }
}
I can't really understand the purpose of what you're trying to do so the API design is going to need modifications to suit your use-case.
You're going to have similar issues with OrmLite which is a Typed code-first POCO ORM where you're going to run into friction trying to use dynamic types which don't exist at Runtime where you'll likely have an easier time executing Dynamic SQL since it's far easier to generate a string than a .NET Type.
With that said GenericTableExpressions.cs shows an example of changing the Table Name that OrmLite saves a POCO to at runtime:
const string tableName = "Entity1";
using (var db = OpenDbConnection())
{
db.DropAndCreateTable<GenericEntity>(tableName);
db.Insert(tableName, new GenericEntity { Id = 1, ColumnA = "A" });
var rows = db.Select(tableName, db.From<GenericEntity>()
.Where(x => x.ColumnA == "A"));
Assert.That(rows.Count, Is.EqualTo(1));
db.Update(tableName, new GenericEntity { ColumnA = "B" },
where: q => q.ColumnA == "A");
rows = db.Select(tableName, db.From<GenericEntity>()
.Where(x => x.ColumnA == "B"));
Assert.That(rows.Count, Is.EqualTo(1));
}
Which uses these extension methods:
public static class GenericTableExtensions
{
static object ExecWithAlias<T>(string table, Func<object> fn)
{
var modelDef = typeof(T).GetModelMetadata();
lock (modelDef)
{
var hold = modelDef.Alias;
try
{
modelDef.Alias = table;
return fn();
}
finally
{
modelDef.Alias = hold;
}
}
}
public static void DropAndCreateTable<T>(this IDbConnection db, string table)
{
ExecWithAlias<T>(table, () => {
db.DropAndCreateTable<T>();
return null;
});
}
public static long Insert<T>(this IDbConnection db, string table, T obj, bool selectIdentity = false)
{
return (long)ExecWithAlias<T>(table, () => db.Insert(obj, selectIdentity));
}
public static List<T> Select<T>(this IDbConnection db, string table, SqlExpression<T> expression)
{
return (List<T>)ExecWithAlias<T>(table, () => db.Select(expression));
}
public static int Update<T>(this IDbConnection db, string table, T item, Expression<Func<T, bool>> where)
{
return (int)ExecWithAlias<T>(table, () => db.Update(item, where));
}
}
But it's not an approach I'd take personally, if I absolutely needed (and I'm struggling to think of a valid use-case outside of table-based Multitenancy or sharding) to save the same schema in multiple tables I'd just be using inheritance again, e.g:
public class Table1 : TableBase {}
public class Table2 : TableBase {}
public class Table3 : TableBase {}

receiving a json string in C# Web Api 2

I'm trying to do a patch with web api. I keep getting NULL for my json. Please Help
Here is my Json
[{"PartNumber":"AN33016UA-VB"}{"Category":"Chassis"}]
Here is my my class
public class wsCategory
{
public string PartNumber { get; set; }
public string Category { get; set; }
}
Here is my Api Controller
[HttpPatch]
[ActionName("IMDSCategory")]
public HttpResponseMessage IMDSCategory([FromBody]wsCategory jsonbody)
{
var data = jsonbody.PartNumber;
return new HttpResponseMessage(HttpStatusCode.Created);
}
The JSON is inavalid.
[{"PartNumber":"blahblah","Category":"Chassis"}]
I believe the array container will be parsed out correctly, but I'm on a chromebook right now, so I can't check that. If it still fails, drop the [].
based on your method
[HttpPatch]
[ActionName("IMDSCategory")]
public HttpResponseMessage IMDSCategory([FromBody]wsCategory jsonbody){...}
Your JSON is invalid given the model you are trying to parse.
[{"PartNumber":"AN33016UA-VB"}{"Category":"Chassis"}]
should be
{"PartNumber":"AN33016UA-VB","Category":"Chassis"}

Return Custom Json Result in WCF REST Service

In Wcf Rest serivce how to return custom Json?
Like: if i have a Json result for a model
{'name':'R2D2', 'location':'starship'}
I want to have a custom Json Result like
{'Status':'OK', 'data':{'name':'R2D2', 'location':'starship'}, 'Message':'',...
}
How can i achieve this function?
I did some how achieve it... Not sure if it is the best way.
public class JsonResult<T>
{
public string Status { get; set; }
public string Message { get; set; }
public T Data { get; set; }
}
in Service
[WebGet(ResponseFormat=WebMessageFormat.Json)]
JsonResult<Robot> TestJson();
It does Give me my desired Result.
Is this the best way? or There are other methods Too?
Thanks
If you want to control your response format you can implement a custom IDispatchMessageFormatter (a custom WebMessageFormat).
There is a nice post in here: http://serena-yeoh.blogspot.co.il/2013/02/wcf-rest-custom-webmessageformat.html

How to get the request object from wcf message?

I have a WCf service with Contracts shown below.
[MessageContract]
public class ServiceRequest
{
[MessageBodyMember]
public int RequestId { get; set; }
[MessageBodyMember]
public OrderDetails OrderDetails { get; set; }
}
[DataContract]
public class OrderDetails
{
[IsLogRequired]
public int OrderId { get; set; }
[IsLogRequired]
public int Quantity { get; set; }
public string CustomerName { get; set; }
}
[IsLogRequired] is custom Attribute.
We need to get all properties in the request which have "[IsLogRequired]" attribute when the request is received. We want to do it as generic solution so that it can be plugged into all services.
We thought of using "MessageInspector" to do this implementing "IDispatchMessageInspector".
How do i get the actual request object from "System.ServiceModel.Channels.Message" parameter of IDispatchMessageInspector.AfterReceiveRequest() method?
Please correct me if i am using a wrong interface or wrong method. Any other solution to this?
I am assuming that "[IsLogRequired] is custom property." means a custom attribute...
Simple answer is that there is no solution to transfer custom attributes that are decorating the data contract as you described it.
Data contracts should be pure and not encumbered by business logic. The know how about the what should be done with various fields belongs to a service implementation.
Possible approach could look like this:
public class OrderService : IOrderService
{
private void ProcessOrder(Order order)
{
var ra = new AuditMetadataResourceAccess();
MethodInfo[] fieldsToLog = ra.GetLoggingFields(typeof(OrderDetal));
if (fieldsToLog.Any())
{
var logger = new LogingEngine();
logger.Log(fieldsToLog, order.OrderDetails);
}
}
}
You could move this implementation inside message inspector or operation invoker. Carlos Figueira has extensive description of each WCF extensibility point.
"How do i get the actual request object from "System.ServiceModel.Channels.Message" parameter of IDispatchMessageInspector.AfterReceiveRequest() method?"
I am assuming you are referring to Web request. WebOperationContext.Current but you need to have ASP.NET Compatibility Mode turned on.

Categories