Change status value from int to string - c#

I have a status property with int values in array of objects. Below is the output of array of objects.
[
{
"enterpriseServiceId": 1,
"enterpriseServices": {},
"status": 3,
"id": 1,
"createdOn": "2017-12-29T17:58:15.4855946",
"createdBy": "System",
"modifiedOn": "2017-12-29T17:58:15.4855946",
"modifiedBy": "System"
},
{
"enterpriseServiceId": 2,
"enterpriseServices": {},
"status": 1,
"id": 2,
"createdOn": "2017-12-29T17:58:15.4855946",
"createdBy": "System",
"modifiedOn": "2017-12-29T17:58:15.4855946",
"modifiedBy": "System"
}
]
The status property is enum value type. I am trying to convert that to string value so it is easier to read when it is returned in output.
Below is my code that gets the data from sql server database.
ENUM
namespace CoreLibrary.Models.Enums
{
public static class Common
{
public enum Status
{
Active = 1,
InActive,
Completed,
Failed,
InProgress,
Pause,
Resume,
Skip,
Running
}
}
}
Entity Model:
namespace CoreLibrary.Models.Entities
{
public class Deployments : BaseProperties
{
public int EnterpriseServiceId { get; set; }
[ForeignKey("EnterpriseServiceId")]
public virtual EnterpriseServices EnterpriseServices { get; set; }
public Common.Status Status { get; set; }
}
}
Method that retrieves data from database:
[HttpGet("~/api/Deployments/GetWithJoins")]
public JsonResult GetWithJoins()
{
try
{
// includeList for including data from external tables (JOIN Query)
var includeList = new List<Expression<Func<Deployments, object>>>();
includeList.Add(d => d.EnterpriseServices);
IEnumerable<Deployments> result = _repository.GetByIdWithJoins(queryable: includeList).ToList();
return Json(result);
}
catch (Exception ex)
{
var innerException = ex.InnerException == null ? null : ex.InnerException.Message.ToString();
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { status = "failed", message = ex.Message.ToString(), innerException = innerException });
}
}
The result variable returns the output I shared at very beginning of this post. I am trying to convert status to return string value instead of int.
I am not sure if thats even possible or it is the right way to output of status int to string value?
I tried online, but I havent found a solution to my requirement. I would appreciate any help you guys can give. :)

When we call JSON(someObject), ASP.NET uses its JavaScriptSerializer to create a JsonResult. The default configuration of the JavaScriptSerializer converts enums to their integer representation.
We can configure the serializer to use a string representation of enums instead. There are details on how to do that here: JSON serialization of enum as string
If that approach does not appeal, then you can use LINQ to map to an anonymous object using Enum.ToString(). Here is an example:
var result = deployments.Select(x =>
{
return new
{
Status = x.Status.ToString(),
x.EnterpriseServiceId
};
});
While the LINQ approach will work, it might lead to maintenance problems in the long-term.

Related

NJsonSchema C# - Change Generated Value Type

I am using NJsonSchema CsharpGenerator 10.1.24 and have the below schema I am using to generate a POCO:
"description": "schema validating people and vehicles",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [ "oneOf" ],
"properties": { "oneOf": [
{
"firstName": {"type": "string"},
"lastName": {"type": "string"},
"sport": {"type": "string"}
},
{
"vehicle": {"type": "string"},
"price":{"type": "number"}
}
]
}
}
How can I get the generated C# class to have a decimal type for price instead of the default double?
public double Price { get; set;}
I tried using a custom static method with the generator settings JsonSerializerSettingsTransformationMethod property but nothing changed.
You can try this,
Create CustomTypeResolver
public class CustomTypeResolver : CSharpTypeResolver
{
...
public override string Resolve(JsonSchema schema, bool isNullable, string typeNameHint)
{
if (schema == null)
{
throw new ArgumentNullException(nameof(schema));
}
schema = GetResolvableSchema(schema);
if (schema == ExceptionSchema)
{
return "System.Exception";
}
var type = schema.ActualTypeSchema.Type;
if (type.HasFlag(JsonObjectType.Number))
{
return isNullable ? "decimal?" : "decimal"; ;
}
return base.Resolve(schema, isNullable, typeNameHint);
}
...
}
Generate the class,
var jsonSchema = File.ReadAllText("json1.json");
var schema = JsonSchema.FromJsonAsync(jsonSchema).GetAwaiter().GetResult();
var settings = new CSharpGeneratorSettings();
var typeResolver = new CustomTypeResolver(settings);
var generator = new CSharpGenerator(schema, settings, typeResolver);
var code = generator.GenerateFile();
#tontonsevilla, How would you return both objects under oneOfs to be included in C# POCO? In example above by #user2966445 it will only generate the first item under oneOfs for me, I will only get the POCO with firstName, lastName and sport properties in the POCO & not include vehicle and price. So, when deseriazing the json to POCO it blows up if json payload contains vehicle & price.
One thing I noticed in the NJsonSchema.JsonSchema objects "Resolve" method, it also calls "RemoveNullability" method internally and this code which only returns first item in the oneOfs and not sure how to get around it.
public JsonSchema RemoveNullability( JsonSchema schema )
{
return schema.OneOf.FirstOrDefault( ( JsonSchema o ) => !o.IsNullable( SchemaType.JsonSchema ) ) ?? schema;
}

Swashbuckle SchemaFilter for api operation parameters

I have succesfully created ISchemaFilter to extend swagger.json enum property definitions for code generation purposes as described here. Here is my current SchemaFilter.Apply method:
public void Apply(Schema schema, SchemaFilterContext context)
{
if (context.SystemType.IsEnum)
{
var names = Enum.GetNames(context.SystemType);
var values = Enum.GetValues(context.SystemType);
var desc = "";
foreach (var value in values)
{
var intValue = Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
desc += $"{intValue}={value},";
}
desc = desc.TrimEnd(',');
schema.Extensions.Add("x-enumNames", names);
schema.Extensions["description"] = desc;
}
}
SchemaFilter works properly on my model definitions where model class has member with enum type. Following there is example of output: resolution-field, which is enum type, notice custom x-enumNames and modified description fields:
resolution: {
format: "int32",
enum: [
1,
2,
3,
4
],
type: "integer",
x-enumNames: [
"Hour",
"Day",
"Month",
"Year"
],
description: "1=Hour,2=Day,3=Month,4=Year"
}
Problem is that SchemaFilter does not extend enum types which are in operation parameters. For example following api-method has parameter resolution:
public async Task<ActionResult<ReturnType>> GetData(Models.ResolutionEnum resolution)
And this produces following operation parameter definition to swagger.json (notice missing x-EnumNames):
{
name: "resolution",
in: "query",
required: true,
type: "integer",
format: "int32",
enum: [
1,
2,
3,
4
]
}
Is there any way mechanism to extend swagger enum-schemas which are part of method parameters?
Thank to another answer under this question, I found that there are multiple extension points in Swashbuckle.AspNetCore.SwaggerGen namespace. IParameterFilter is just what I want, and I was able to inject x-enumNames to method parameter definitions.
Following is parameter filter which I made:
public class ModifyParametersFilter : IParameterFilter
{
public void Apply(IParameter parameter, ParameterFilterContext context)
{
var type = context.ParameterInfo?.ParameterType;
if (type == null)
return;
if (type.IsEnum)
{
var names = Enum.GetNames(type);
var values = Enum.GetValues(type);
var desc = "";
foreach (var value in values)
{
var intValue = Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
desc += $"{intValue}={value},";
}
desc = desc.TrimEnd(',');
if (!parameter.Extensions.ContainsKey("x-enumNames"))
parameter.Extensions.Add("x-enumNames", names);
}
}
}
As other filters, this can be activated in Startup.cs with following snippet:
services.AddSwaggerGen(c =>
{
..
c.ParameterFilter<ModifyParametersFilter>();
}
Try with an IDocumentFilter, I have injected x-stuff using it, here is a sample:
public class InjectXStuff : IDocumentFilter
{
public void Apply(SwaggerDocument s, DocumentFilterContext c)
{
PathItem path = s.Paths.Where(x => x.Key.Contains("Values")).First().Value;
path.Post.Parameters.FirstOrDefault().Extensions.Add("x-stuff", "123456");
}
}
the problem there is that you need to know the path in advanced, not sure if there is a pattern you can use in your code to identify those that are enums...

Labeling values returned from API

This method returns a bool and a string -
public (bool active, string name) Report()
{
}
From my controller, I call it like this -
public IActionResult Credit([FromBody] Data data)
{
return Ok(Report())
}
The response I get is something like this -
{
"item1": false,
"item2": "Your name"
}
How do I get this response instead -
{
"Active": false,
"Name": "Your name"
}
The quick and easy way would be to return an anonymous type, taking the values from the returned tuple
public IActionResult Credit([FromBody] Data data)
{
//...
var report = Report();
return Ok(new
{
Active = report.active,
Name = report.name
})
}
Ideally you should return a strongly typed model that can be returned from the API
public class ReportModel
{
public string Name { get;set; }
public bool Active { get;set; }
}
and update accordingly
public ReportModel Report()
{
//...
}
public IActionResult Credit([FromBody] Data data)
{
//...
var report = Report();
return Ok(report);
}
Value tuples (as you are using for the return from your Report() method) are just syntactic sugar around a ValueTuple<T,T,...,T> object. Therefore, the real property names are not active and name but, in fact, item1 and item2.
So your method gets converted to something like this:
[return: TupleElementNames(new string[] {
"active",
"name"
})]
public ValueTuple<bool, string> Report()
How do you resolve this? You should create a model that reflects what you want to return:
public class ActiveName
{
public string Name { get;set;}
public bool Active {get;set;}
}
and then change your method to return this ActiveName type.
Another way is to return an anonymous type as dynamic, but I recommend against this approach since using dynamic introduces the potential for runtime errors if mistakes are made. If you're just using it to return from your API method, then it's probably OK.
public dynamic Report()
{
return new { name = "abc", active = true };
}
public IActionResult Credit([FromBody] Data data)
{
var x = Report();
return Ok(new {Active = x.Item1, UserName = x.Item2});
}

How can I parse instance properties by using json data?

I try to parse json data to List<Employee> instance. But I don't want to use Json-to-C# tool for creating a shadow from json pattern. I want to take values only. Maybe I can use keys to take values (Employee). I want to fill a List of Employee.
My Json:
{
"type":"SUCCESS",
"msg":"Container RBFFiyatlama2_1.0.1 successfully called.",
"result":{
"execution-results":{
"results":[
{
"value":2,
"key":""
},
{
"value":{
"com.myteam.rbffiyatlama2.Employee":{
"salary":2400.0,
"age":35,
"cofactor":0.2
}
},
"key":"Employee0"
},
{
"value":{
"com.myteam.rbffiyatlama2.Employee":{
"salary":4800.0,
"age":35,
"cofactor":0.2
}
},
"key":"Employee1"
}
],
"facts":[
{
"value":{
"org.drools.core.common.DefaultFactHandle":{
"external-form":"0:88:1504512052:1504512052:160:DEFAULT:NON_TRAIT:com.myteam.rbffiyatlama2.Employee"
}
},
"key":"Employee0"
},
{
"value":{
"org.drools.core.common.DefaultFactHandle":{
"external-form":"0:89:213603577:213603577:159:DEFAULT:NON_TRAIT:com.myteam.rbffiyatlama2.Employee"
}
},
"key":"Employee1"
}
]
}
}
}
How can I fill Employee without creating any C# class by using above json.
public class Employee
{
public int age { get; set; }
public double cofactor { get; set; }
public int salary { get; set; }
}
You could use dynamics. The following should do what you're after and it's all native:
string jsonString = YourGetJsonStringMethod();
List<Employee> employees = new List<Employee>();
dynamic data = System.Web.Helpers.Json.Decode(jsonString);
dynamic results = data["result"]["execution-results"]["results"];
if (results.Length > 1)
{
for (var i = 1; i < results.Length; i++)
{
var dynamicEmployee = results[i]["value"]["com.myteam.rbffiyatlama2.Employee"];
dynamicEmployee["salary"] = (int) dynamicEmployee["salary"];
var encoded = System.Web.Helpers.Json.Encode(dynamicEmployee);
employees.Add(System.Web.Helpers.Json.Decode<Employee>(encoded));
}
}
You will obviously need to include System.Web.Helpers in your references, which you can find under Assemblies > Extensions in your Visual Studio Reference Manager.
Bear in mind that this code may raise an exception when you're debugging. If so, refer to this question for the solution.
This code "just works". I will leave it to you to do validation, null-checking and exception catching.

How to update a nested document in a mongodb with c#

I hope someone can help me to understand how I can update a document in a mongodb.
My problem is that i have a document which contains an array. And in this array there are objects with a specific ID(like you would find in sql database). Now I want to update the data inside those objects if they have the searched id.
A document looks like this
{
"_id": "63dafa72f21d48312d8ca405",
"tasks": [{
"_ref": "63d8d8d01beb0b606314e322",
"data": {
"values": [{
"key": "Deadline",
"value": "2014-10-13"
}]
}
}, {
"_ref": "84dd046c6695e32322d842f5",
"data": {
"values": []
}
}]
}
I did write the method updateProject
public bool updateProject(Project pro, Project dbPro)
{
var collection = db.GetCollection<BsonDocument>("projects");
var filter = Builders<BsonDocument>.Filter.Eq("_id", dbPro.Id);
var update = Builders<BsonDocument>.Update.Set("tasks", pro.Tasks);
var result = collection.UpdateOne(filter, update);
if (result.IsModifiedCountAvailable)
{
if (result.ModifiedCount == 1)
{
return true;
}
}
return false;
}
And thats how a project does look like in c#.
class Project{
public string id;
public List<Task> Tasks;
}
class Task{
public string id;
public List<Value> Values;
}
class Value{
public String key;
public String value;
}
but i cant figure out how i can go deeper to find the searched id.

Categories