How to send Json to Azure Appinsights with c# library - azure-application-insights

I'm implementing the Azure's Application Insights and the API I found is I can only send there Dictionary of type string and string. Also if I use TraceTelemetry it has properties on it which again is dictionary of string and string.
However when I add one field to the custom properties (cars in my case) which has value of serialized json it will result in such a payload being sent to the Application Insights.
"baseData": {
"ver": 2,
"message": "Test Message",
"properties": {
"cars": "[{\"Id\":0,\"Price\":{\"Value\":12.32,\"Currency\":.....
}
}
notice the backslash making it one json value.
But the appinsight portal will understand it - and parse it.
So I can use Microsoft provided C# API but it just looks ugly and seems like the API is JSON anyway, so why is API limited to Dictionary<string, string> ?

It is because of filtering in Azure Portal. The main purpose of Properties (Dictionary<string, string>) is provide the ability to find specified requests, exceptions etc. You are also limited by count of properties (it was about 200). The typical properties are: "username", "isAuthenticated", "role", "score", "isAnonymous", "portalName", "group", "product" atc. Typically global properties.
If you want to send whole object / json, you can use TrackTrace(). You can find all the traces regarding to concrete request in portal.

Related

Can I configure asp.net so some responses are serialized as camelCase and some as PascalCase?

I have an API with two clients: OldClient and newClient. I currently have this in Startup.cs so my json responses are serialized as PascalCase, i.e. as per all my .net objects which have first letter capitalized.
services.AddControllers().AddJsonOptions(jsonOptions =>
{
// So json output is like 'SomeId' instead of 'someId':
jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null;
...
}
OldClient loves this format. However, newClient would really prefer camelCase.
Is there a way I can configure my app to respond with camelCase for newClient requests and PascalCase for OldClient requests? newClient can send a header to indicate that it wants camelCase.
You can check out this issue on aspnetcore's github page
The possibility of using specific JSON Serializer Options on a per-controller basis hasn't been implemented yet. It has been moved to ".NET 8 planning", which means it's still a ways-away.
Meanwhile, you could work around this issue by:
For data reception and model-binding, you could create a Custom ModelBinder by implementing IModelBinder interface in a ModelBinderAttribute in order to utilize your specific JSON Serialization options. Then, you could simply add the attribute to the endpoints where you need it.
For data responses, you could simply use:
return new JsonResult([object], [CustomJSONSerializationSettings]);
It's quite annoying to have to modify these per-endpoint, but it seems like it's the only way until the feature is added in .net 8 (if we're lucky).

How can I hide System.Exception errors on .NET Core?

I try to improve myself with .NET Web API now and I am trying to return a custom error in Swagger. But when returning this custom error, I can see the error is on which line. How can I do to prevent this?
public async Task<BookCreateDTO> CreateBook(BookCreateDTO bookCreateDto)
{
if (await _context.Books.AnyAsync(x => x.Name == bookCreateDto.Name))
{
throw new BookExistException("Book already exist");
}
var book= _mapper.Map<Book>(bookCreateDto);
_context.Books.Add(book);
await _context.SaveChangesAsync();
return book;
}
What should I do to see only this exception message in the Swagger response?
Thank you for your help.
Exceptions should be exceptional: Don't throw exceptions for non-exceptional errors.
I don't recommend specifying your web-service's response DTO type in the C# action method return type because it limits your expressiveness (as you're discovering).
Instead use IActionResult or ActionResult<T> to document the default (i.e. HTTP 2xx) response type and then list error DTO types in [ProducesResponseType] attributes with their corresponding HTTP status codes.
This also means that each response status code should only be associated with a single DTO type.
While Swagger is not expressive enough to allow you to say "if the response status is HTTP 200 then the response body/DTO is one-of DtoFoo, DtoBar, DtoQux", in-practice a well-designed web-service API should not exhibit that kind of response DTO polymorphism.
And if it didn't, how else is a client supposed to know what the type is just from the HTTP headers? (Well, you could put the full DTO type-name in a custom HTTP response header, but that introduces other problems...)
For error conditions, add the errors to ModelState (with the Key, if possible) and let ASP.NET Core handle the rest for you with ProblemDetails.
If you do throw an exception, then ASP.NET Core can be configured to automatically render it as a ProblemDetails - or it can show the DeveloperExceptionPage - or something else entirely.
I note that a good reason to not throw an exception inside a Controller for non-exceptional exceptions is because your logging framework may choose to log more details about unhandled exceptions in ASP.NET Core's pipeline, which would result in useless extraneous entries in your logs that make it harder to find "real" exceptions that you need to fix.
Document the DTOs used, and their corresponding HTTP status codes, with [ProducesResponseType]: this is very useful when using Swagger/NSwag to generate online documentation and client libraries.
Also: do not use EF entity types as DTOs or ViewModels.
Reason 1: When the response (with EF entity objects) is serialized, entities with lazy-loaded properties will cause your entire database object-graph to be serialized (because the JSON serializer will traverse every property of every object).
Reason 2: Security! If you directly accept an EF entity as an input request body DTO or HTML form model then users/visitors can set properties arbitrarily, e.g. POST /users with { accessLevel: 'superAdmin' }, for example. While you can exclude or restrict which properties of an object can be set by a request it just adds to your project's maintenance workload (as it's another non-local, manually-written, list or definition in your program you need to ensure is kept in-sync with everything else.
Reason 3: Self-documenting intent: an entity-type is for in-proc state, not as a communications contract.
Reason 4: the members of an entity-type are never exactly what you'll want to expose in a DTO.
For example, your User entity will have a Byte[] PasswordHash and Byte[] PasswordSalt properties (I hope...), and obviously those two properties must never be exposed; but in a User DTO for editing a user you might want different members, like NewPassword and ConfirmPassword - which don't map to DB columns at all.
Reason 5: On a related note to Reason 4, using Entity classes as DTOs automatically binds the exact design of your web-service API to your database model.
Supposing that one day you absolutely need to make changes to your database design: perhaps someone told you the business requirements changed; that's normal and happens all the time.
Supposing the DB design change was from allowing only 1 address per customer (because the street addresses were being stored in the same table as customers) to allowing customers to have many addresses (i.e. the street-address columns are moved to a different table)...
...so you make the DB changes, run the migration script, and deploy to production - but suddenly all of your web-service clients stop working because they all assumed your Customer object had inline Street address fields but now they're missing (because your Customer EF entity types' don't have street-address columns anymore, that's over in the CustomerAddress entity class).
If you had been using a dedicated DTO type specifically for Customer objects then during the process of updating the design of the application you would have noticed builds breaking sooner (rather than inevitably later!) due to C# compile-time type-checking in your DTO-to-Entity (and Entity-to-DTO) mapping code - that's a benefit right there.
But the main benefit is that it allows you to completely abstract-away your underlying database design - and so, in our example, if you have remote clients that depend on Customer address information being inline then your Customer DTO can still emulate the older design by inlining the first Customer Address into the original Customer DTO when it renders its JSON/XML/Protobuf response to the remote client. That saves time, trouble, effort, money, stress, complaints, firings, unnecessary beatings, grievous bodily harm and a scheduled dental hygienist's appointment.
Anyway, I've modified your posted code to follow the guidance above:
I added [ProducesResponseType] attributes.
I appreciate it is redundant to specify the default response type BookCreateDTO twice (in [ProducesResponseType] as well as ActionResult<BookCreateDTO> - you should be able to remove either one of those without affecting Swagger output.
I added an explicit [FromBody], just to be safe.
If the "book-name is unused" check fails, it returns the model validation message in ASP.NET's stock BadRequest response, which is rendered as an IETF RFC 7807 response, aka ProblemDetails instead of throwing an exception and then hoping that you configured your ASP.NET Core pipeline (in Configure()) to handle it as a ProblemDetails instead of, say, invoking a debugger or using DeveloperExceptionPage.
Note that in the case of a name conflict we want to return HTTP 409 Conflict and not HTTP 400 Bad Request, so the conflictResult.StatusCode = 409; is overwritten.
The final response is generated from a new BookCreateDTO instance via AutoMapper and Ok() instead of serializing your Book entity object.
[ProducesResponseType(typeof(BookCreateDTO), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status409Conflict)]
public async Task< ActionResult<BookCreateDTO> > CreateBook( [FromBody] BookCreateDTO bookCreateDto )
{
// Does a book with the same name exist? If so, then return HTTP 409 Conflict.
if( await _context.Books.AnyAsync(x => x.Name == bookCreateDto.Name) )
{
this.ModelState.Add( nameof(BookCreateDTO.Name), "Book already exists" );
BadRequestObjectResult conflictResult = this.BadRequest( this.ModelState );
// `BadRequestObjectResult` is HTTP 400 by default, change it to HTTP 409:
conflictResult.StatusCode = 409;
return conflictResult;
}
Book addedBook;
{
addedBook = this.mapper.Map<Book>( bookCreateDto );
_ = this.context.Books.Add( book );
_ = await this.context.SaveChangesAsync();
}
BookCreateDTO responseDto = this.mapper.Map<BookCreateDTO >( addedBook );
return this.Ok( responseDto );
}

How to create swagger documentation for dynamic request/response

We have an API application which is driven dynamically based on SQL defined metadata. This API app is a reporting application and the report is driven by what kind of request is passed into the API. This means if JSON request is passed like this -
ex 1
{
"Field1": "Value1"
"GroupBy": ["GroupByValue1", "GroupByValue2"]
}
Then it gives below resultset -
{
"GroupByValue1": "SomeValue1"
"GroupByValue2": "SomeValue2"
... other fields based on GroupBy1 and GroupBy2
}
ex 2
{
"Field1": "Value1"
"GroupBy": ["GroupByValue3"]
}
Then it gives below resultset -
{
"GroupByValue3": "SomeValue1"
... other fields based on GroupBy3
}
So the mapping of request v/s fields for that request is defined in the SQL database.
And we need to generate swagger documentation for this kind of dynamic requests. So my question is since we use swashbuckle for swagger documentation, we have to give it specific resultset based on the request being passed. Now we have APIs to give us those request/resultset relationship, but is there a way to generate documentation completely dynamically based on this API (using c# code or typescript) that gives us request/resultset relationship.
You can create dynamic Swagger documentation using IDocumentFilter.
We also use dynamic SQL metadata at this example.

How to remove Cloud Firestore field type specifiers when using REST API?

I totally made up the name "type specifiers." What I mean is the stringValue key in front of a value. Usually I would expect a more-standard response: "name" : "name_here".
{
"fields": {
"name": {
"stringValue": "name_here"
}
}
}
Is it possible to remove those when making a GET call?
More importantly, it be nice to understand why it's structured like it is. Even for POST-ing data? The easy answer is probably because Cloud Firestore, unlike Realtime Database, needs to know the specific types, but what are all the deeper reasons? Is there an "official" name for formatting like this where I could do more research?
For example, is the reasoning any related to Protocol Buffers? Is there a way to request a protobuf instead of JSON?
Schema:
Is it possible to remove those when making a GET call?
In short No. The Firestore REST API GET returns an instance of Document.
See https://firebase.google.com/docs/firestore/reference/rest/v1beta1/projects.databases.documents#Document
{
"name": string,
"fields": {
string: {
object(Value)
},
...
},
"createTime": string,
"updateTime": string,
}
Regarding the "Protocol Buffer": When the data is deserialized you could just have a function to convert into the structure you wish to use, e.g. probably using the protocol buffers if you wish but as there appear to be libraries for SWIFT, OBJECTIVE-C, ANDROID, JAVA, PYTHON, NODE.JS, GO maybe you won’t need to use the REST API and craft a Protocol Buffer.
Hopefully address your “More Importantly” comment:
As you eluded to in your question Firestore has a different data model to the Realtime Database.
Realtime database data model allows JSON objects with the schema and keywords as you want to define it.
As you point out, the Firestore data model uses predefined schemas, in that respect some of the keywords and structure cannot be changed.
The Cloud Firestore Data Model is described here: https://firebase.google.com/docs/firestore/data-model
Effectively the data model is / where a document can contain a subcollection and the keywords “name”, “fields”, “createdTime”, “upTime” are in a Firestore document (a pre-defined JSON document schema).
A successful the Firestore REST API GET request results in a Document instance which could contain collection of documents or a single document. See https://firebase.google.com/docs/firestore/reference/rest/. Also the API discovery document helps give some detail about the api:
https://firestore.googleapis.com/$discovery/rest?version=v1beta1
An example REST API URL structure is of the form:
https://firestore.googleapis.com/v1beta1/projects/<yourprojectid>/databases/(default)/documents/<collectionName>/<documentID>
It is possible to mask certain fields in a document but still the Firestore Document schema will persist. See the three examples GET:
collection https://pastebin.com/98qByY7n
document https://pastebin.com/QLwZFGgF
document with mask https://pastebin.com/KA1cGX3k
Looking at another example, the REST API to run Queries
https://firebase.google.com/docs/firestore/reference/rest/v1beta1/projects.databases.documents/runQuery
the response body is of the form:
{
"transaction": string,
"document": {
object(Document)
},
"readTime": string,
"skippedResults": number,
}
In summary:
The Realtime database REST API will return the JSON for the object according to the path/nodes as per your “more-standard response”.
The Firestore REST API returns a specific Firestore predefined response structure.
There API libraries available for several language so maybe it’s not necessary to use the REST API and craft your own Protocol Buffer but if you needed to you it’s probably feasible.
I don't understand why somebody just say that you can't and don't try think some solution for help! Seriously that this is a really problem solver?
Anyway, I created a script that will help you (maybe it's late now hahaha).
The script encode json and after replace it as string to modify and remove Google type fields (low process).
It's a simple code, I know that you can improve it if necessary!
WARNING!!
Maybe you will have problems with values that contain '{}' or '[]'. This can be solved with a foreach that convert all strings that contains this elements in other char (like '◘' or '♦', some char that you know that doesn't will be in value.
Ex.: Hi {Lorena}! ------> Hi ◘Lorena♦!
After the process, convert again to '{}' or '[]'
YOU CAN'T HAVE FIELDS WITH THE SAME NAME THAT GOOGLE FIELDS
Ex.: stringValue, arrayValue, etc
You can see and download the script in this link:
https://github.com/campostech/scripts-helpers/blob/master/CLOUD%20STORE%20JSON%20FIELDS%20REMOVER/csjfr.php

Web API Complex Data in Get

I am using Web APi, as I am new to this, I dont know much about it.
I am trying to implement search, as of now I am starting with only text search, but later there may be huge search criteria. for one text that is easy, as web api works good with
primitive data types. Now I want to create a class of filter, say the pagenumber , the pagesize also all the search criteria, so I created a class. I have created a MVC application which is communicating with the web api, the web api returns Json data, then I de-serialize it to model. I am stuck with the complex object part, also as of now I am using a list to get the data, later that will be replaced by data base. Following is the code.
public IEnumerable<Document> Get(PaggingDetails request) //public async Task<IEnumerable<Note>> GetNotes() for Async (DB)
{
return _repository.GetAll(pagedetails.PageNumber, pagedetails.PageSize, pagedetails.PageFilter);
//return await db.Notes.ToListAsync<Note>(); for async
}
public string GetPage(int pagenumber,int pagesize,string pagefilter)
{
try
{
PaggingDetails PageDetails = new PaggingDetails();
PageDetails.PageFilter = pagefilter;
PageDetails.PageSize = pagesize;
PageDetails.PageNumber = pagenumber;
return new System.Net.WebClient().DownloadString
("http://.../api/Document/?pagedetails=" +
PageDetails);
//new HttpClient().GetStringAsync("http://localhost:18545/api/Emails"); for async
//also pass parameters
}
catch (Exception ex)
{
}
return "";
}
By deafult, you cannot use a class as the type of parameter of a GET Web API action. You need to use individual parameters of single types.
If you want to use a class as parameter nothing stops you to use a POST action, in which you can include the data without any problem.
However you can force a complex parameter of a GET action to be read from the URI by decorating the comples attribute with [FromUri].
You can read this document to better understand Web API parameter binding:
Parameter Binding in ASP.NET Web API
By default, Web API uses the following rules to bind parameters:
If the parameter is a “simple” type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string. (More about type converters later.)
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
This is the standard way of working. If you use the [FromUri] attribute, the action selector won't be able to choose between different Get methods that receive different complex types. If you use a route with controller and action segments, you won't have that problem, becaus ethe actions selector will choose by action name, no matter what the aprameters are.
I don't like using the [FromUri] for this reason, and beacuse it's not the natural way to work with the GET action. But you can use it with the necessary precautions.

Resources