JSON Response to object and C# Best Practice? [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am using an API to make requests to to a process.
The response from the server is not always exactly the same size or dimension to compare it to an array.
Response look like this in json...
{
"type": "object",
"properties": {
"ResponseHeader": {
"type": "object",
"properties": {
"RequestID": {
"type": "string"
},
"Status": {
"type": "object",
"properties": {
"severity": {
"type": "string"
},
"statusDesc": {
"type": "string"
},
"sStatusCode": {
"type": "string"
},
"statusCode": {
"type": "string"
},
"AStatus": {
"type": "array",
"items": {
"properties": {
"statusCode": {
"type": "string"
},
"serverStatusCode": {
"type": "string"
},
"severity": {
"type": "string"
},
"statusDesc": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
},
"contact": {
"type": "object",
"properties": {
"acNumber": {
"type": "string"
},
"floatName": {
"type": "string"
},
"pData": {
"type": "object",
"properties": {
"fullName": {
"type": "string"
},
"familyName": {
"type": "string"
}
}
},
"iIdent": {
"type": "array",
"items": {
"properties": {
"type": {
"type": "string"
},
"number": {
"type": "string"
},
"description": {
"type": "string"
},
"verificationResults": {
"type": "string"
}
},
"type": "object"
}
},
"emp": {
"type": "array",
"items": {
"properties": {
"employer": {
"type": "string"
},
"Income": {
"type": "string"
},
"Title": {
"type": "string"
},
"empId": {
"type": "string"
}
},
"type": "object"
}
},
"miscData": {
"type": "array",
"items": {
"properties": [],
"type": "object"
}
},
"pAddress": {
"type": "array",
"items": {
"properties": {
"addType": {
"type": "string"
},
"add1": {
"type": "string"
},
"add2": {
"type": "string"
},
"city": {
"type": "string"
},
"zipCode": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
}
What is the best practice / correct way to create this as an object in C#?
Do I create a class?
Do I create it as an array?
I know that I have seen a few questions with answers related to this but none of them talk about best practice.

The easiest thing that comes to mind is using visual studio's paste special ability. That creates a class based off of a piece of Json or XML that you have in your clipboard.

Related

NJsonSchema C# - Remove $ref fields and replace by the actual structure

I'm using NJsonSchema to convert a normal Json to Schema.
However, NJsonSchema returns the Schema with $ref fields, but I want to have the actual structure.
For example:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Property1": {
"$ref": "#/definitions/Property1"
},
"Property2": {
"$ref": "#/definitions/Property2"
},
"Property3": {
"type": "array",
"items": {
"$ref": "#/definitions/Property3"
}
},
"Property4": {
"type": "array",
"items": {
"$ref": "#/definitions/Property4"
}
}
},
"definitions": {
"Property1": {
"type": "object",
"properties": {
"Property1_1": {
"type": "string"
},
"Property1_2": {
"type": "boolean"
},
"Property1_3": {
"type": "integer"
},
"Property1_4": {
"type": "integer"
}
}
},
"Property2": {
"type": "object",
"properties": {
"Property2_1": {
"$ref": "#/definitions/Property2_1"
},
"Property2_2": {
"$ref": "#/definitions/Property2_2"
}
}
},
"Property2_1": {
"type": "object",
"properties": {
"Property2_1_1": {
"type": "array",
"items": {
"$ref": "#/definitions/Property2_1_1"
}
},
"Property2_1_2": {
"type": "array",
"items": {
"$ref": "#/definitions/Property2_1_2"
}
},
"Property2_1_3": {
"type": "array",
"items": {
"$ref": "#/definitions/Property2_1_3"
}
},
"Property2_1_4": {
"type": "array",
"items": {
"$ref": "#/definitions/Property2_1_4"
}
}
}
},
"Property2_1_1": {
"type": "object",
"properties": {
"filename": {
"type": "string"
},
"interface": {
"type": "string"
},
"_Comment": {
"type": "string"
}
}
},
"Property2_1_2": {
"type": "object",
"properties": {
"filename": {
"type": "string"
},
"interface": {
"type": "string"
},
"_Comment": {
"type": "string"
}
}
},
"Property2_1_3": {
"type": "object",
"properties": {
"filename": {
"type": "string"
},
"interface": {
"type": "string"
}
}
},
"Property2_1_4": {
"type": "object",
"properties": {
"filename": {
"type": "string"
},
"interface": {
"type": "string"
}
}
},
"Property2_2": {
"type": "object",
"properties": {
"dtm_file_name": {
"type": "string"
},
"dtm_file_name_ext": {
"type": "string"
},
"_Comment": {
"type": "string"
}
}
},
"Property3": {
"type": "object",
"properties": {
"offset": {
"type": "integer"
},
"value": {
"type": "string"
}
}
},
"Property4": {
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"offset": {
"type": "integer"
}
}
}
}
}
Got the above JSON using:
JsonSchema bodySchema = JsonSchema.FromSampleJson(jsonStr);
string schemaStr = bodySchema.ToJson();
How can I remove these references and replace to the actual structures?
Such as:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Property1": {
"type": "object",
"properties": {
"Property1_1": {
"type": "string"
},
"Property1_2": {
"type": "boolean"
},
"Property1_3": {
"type": "integer"
},
"Property1_4": {
"type": "integer"
}
}
},
"Property2": {
"type": "object",
"properties": {
"Property2_1": {
"type": "object",
"properties": {
"Property2_1_1": {
"type": "array",
"items": {
"type": "object",
"properties": {
"filename": {
"type": "string"
},
"interface": {
"type": "string"
},
"_Comment": {
"type": "string"
}
}
}
},
"Property2_1_2": {
"type": "array",
"items": {
"type": "object",
"properties": {
"filename": {
"type": "string"
},
"interface": {
"type": "string"
},
"_Comment": {
"type": "string"
}
}
}
},
"Property2_1_3": {
"type": "array",
"items": {
"type": "object",
"properties": {
"filename": {
"type": "string"
},
"interface": {
"type": "string"
}
}
}
},
"Property2_1_4": {
"type": "array",
"items": {
"type": "object",
"properties": {
"filename": {
"type": "string"
},
"interface": {
"type": "string"
}
}
}
}
}
},
"Property2_2": {
"type": "object",
"properties": {
"dtm_file_name": {
"type": "string"
},
"dtm_file_name_ext": {
"type": "string"
},
"_Comment": {
"type": "string"
}
}
}
}
},
"Property3": {
"type": "array",
"items": {
"type": "object",
"properties": {
"offset": {
"type": "integer"
},
"value": {
"type": "string"
}
}
}
},
"Property4": {
"type": "array",
"items": {
"type": "object",
"properties": {
"attr_name": {
"type": "string"
},
"offset": {
"type": "integer"
}
}
}
}
}
}
Is there any method that does that inside NJsonSchema or some other way?
Regards,
Thiago

Write one test for multiple requests

I have a json from OpenApi that have all Http requests from my project, it looks like that:
{
"openapi": "3.0.1",
"info": {
"title": "TestApi",
"version": "1.0"
},
"paths": {
"/api/Test1/test1/{id}": {
"get": {
"tags": [
"Test1"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Success"
}
}
}
},
"/api/Test2/test2/{id}": {
"get": {
"tags": [
"Test2"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Success"
...
I need to create one test that will check only GET requests that all of them return 200. I know how to test one request for needed status code but how to test multiple requests in one test? And how to correctly take them from json?

NjsonSchema Validation If Property1 is equal to Something then require Property2

I seem to not be able to get const or enum working as part of an if-then-else JSON schema validation.
They seem to be interchangeable when 1 validation value is concerned. (Reference)
Here is my JSON schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Test_Schema",
"description": "A schema for validating a test object",
"type": "object",
"additionalProperties": false,
"properties": {
"GeneralData": {
"type": "object",
"description": "Advsor and admin customer information",
"properties": {
"Name": {
"type": [ "string", "null" ],
"description": "Customer's advisor name"
},
"Age": {
"type": [ "string", "null" ],
"description": "Customer's advisor email"
},
"Location": {
"type": [ "string", "null" ],
"description": "The advisor's manager email'"
}
},
"required": [ "Name", "Location", "Age" ]
},
"ClientData": {
"type": "object",
"description": "Customer's information",
"additionalProperties": false,
"properties": {
"Title": {
"type": [ "string", "null" ]
},
"Forename": {
"type": [ "string", "null" ]
},
"Surname": {
"type": [ "string" ]
}
},
"required": [ "Title" ],
"if": {
"properties": {
"Forename": { "enum": [ "Soameonea" ] }
},
"required": [ "Forename" ]
},
"then": { "required": [ "Surname" ] },
"else": false
}
}
}
If Forename = "Someone" I want Surname to be required.
Here is my jsonObject after serialization:
{
"GeneralData": {
"Name": "Not Relevant",
"Age": "Not Relevant",
"Location": "Not Relevant"
},
"ClientData": {
"Title": "SomeTitle",
"Forename": "Someone",
"Surname": null
}
}
Validation code:
internal void ValidateDataObjectOnSchema()
{
var dataObject = PopulateDataObject();
var json = JsonConvert.SerializeObject(dataObject);
var result = GetSchema().Validate(json);
var errors = result.Select(x =>
{
return new Errors() { Title = x.Property, Description = x.Schema.Description };
});
var i = errors;
}
internal JsonSchema GetSchema()
{
return JsonSchema.FromFileAsync("Test/testSchema.json").Result;
}
Right now it still requires Surname, even though the enum Soameonea != Someone and I only require Title. <== Issue1
In the JSON schema if I set "Surname":{"type":["string","null]} then the error disappears and still I don't get the error if I then change the if condition for the Forename enum to "Someone". <== Issue 2
I cannot get a different validation output if I replace Enum with Const, So if I can get one to work I'm sure the other will follow.
I've found several answers to this question (Answer 1), I try to implement the same thing and for some reason, it fails in my case.
What am I missing?
In the JSON schema if I set "Surname":{"type":["string","null]} then the error disappears
A property with a null value still has a value. If you want to say that the property value must not only exist, but not be null, then add "type": "string" to your then condition.
Update:
As #Relequestial mentioned in one of the comments it seems NJson Schema only supports up to Draft 04, this is why if-then-else did not work and implication should be used instead. Below is my solution with an alternative package.
The same code and json work with the package Newtonsoft.Json.Schema (Reference)
Code:
internal void ValidateDataObjectOnSchemaWithNewtonSoftJson()
{
var dataObject = PopulateDataObject();
var settings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore
};
var jsonDataObjectString = JsonConvert.SerializeObject(dataObject, settings);
JObject jsonDataObject = JObject.Parse(jsonDataObjectString);
var jsonSchemaFile = File.ReadAllText("Test/testSchema.json");
var schema = JSchema.Parse(jsonSchemaFile);
;
IList<ValidationError> messages;
var result = jsonDataObject.IsValid(schema, out messages);
var errors = GetReadableResult(result, messages);
}
private List<Errors> GetReadableResult(bool result, IList<ValidationError> messages)
{
var errors = new List<Errors>();
if (!result)
{
foreach (var error in messages)
{
if (error.ChildErrors.Count > 0)
{
errors.Add(
new Errors()
{
Path = error.ChildErrors.FirstOrDefault()?.Path,
Kind = error.ChildErrors.FirstOrDefault()?.Message
});
}
else
{
errors.Add(new Errors()
{
Path = error.Path,
Kind = error.Message
});
}
}
}
return errors;
}
JsonSchema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Test_Schema",
"description": "A schema for validating a test object",
"type": "object",
"additionalProperties": false,
"properties": {
"GeneralData": {
"type": "object",
"description": "Advsor and admin customer information",
"properties": {
"Name": {
"type": [ "string", "null" ],
"description": "Customer's advisor name"
},
"Age": {
"type": [ "string", "null" ],
"description": "Customer's advisor email"
},
"Location": {
"type": [ "string", "null" ],
"description": "The advisor's manager email'"
}
},
"required": [ "Name", "Location", "Age" ]
},
"ClientData": {
"type": "object",
"description": "Customer's information",
"additionalProperties": false,
"properties": {
"Title": {
"type": [ "string", "null" ]
},
"Forename": {
"type": "string"
},
"Surname": {
"type": [ "string" ]
}
},
"required": [ "Title" ],
"if": {
"properties": {
"Forename": { "enum": [ "Someone" ] }
},
"required": [ "Forename" ]
},
"then": { "required": [ "Surname" ] },
"else": {}
}
}
}
The only addition would be to make the GetReadableResult recursive for Errors which have multiple child items.

JSON single property formatting

I have following JSON:
{
"cap": [
{
"type": "test"
},
{
"type": "test1"
},
{
"type": "test2",
"bla": "tst"
}
]
}
I want every object that have single property to be one line formated
{ "type": "test" }
so the final JSON should be
{
"cap": [
{ "type": "test" },
{ "type": "test1" },
{
"type": "test2",
"bla": "tst"
}
]
}
How to do this in c#?

Deploy IIS Website with CloudFormation template

I have a Visual Studio (C#) deployment package (.zip) that I have pushed up to my S3 storage.
I want to run my CloudFormation script and have it create an instance of an IIS server (I have the script for this) and then deploy the Visual Studio web site to it from the S3 storage.
I'm looking for an example of the temple json that would do that
I have a template that does something similar to what you are looking for. Below is a template that I use. It may be more than you need, because it has an auto scaling group, but it will get you started. Basically, you need the IAM user to interact with cloud formation. The script in the UserData starts cf-init, which does the stuff in the metadata section.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Autoscaling for .net Web application.",
"Parameters": {
"InstanceType": {
"Description": "WebServer EC2 instance type",
"Type": "String",
"Default": "m1.small",
"AllowedValues": [
"t1.micro",
"m1.small",
"m1.medium",
"m1.large",
"m1.xlarge",
"m2.xlarge",
"m2.2xlarge",
"m2.4xlarge",
"c1.medium",
"c1.xlarge",
"cc1.4xlarge",
"cc2.8xlarge",
"cg1.4xlarge"
],
"ConstraintDescription": "Must be a valid EC2 instance type."
},
"IamInstanceProfile": {
"Description": "Name of IAM Profile that will be used by instances to access AWS Services",
"Type": "String",
"Default": "YourProfileName"
},
"KeyName": {
"Description": "The EC2 Key Pair to allow access to the instances",
"Default": "yourkeypair",
"Type": "String"
},
"SpotPriceBid": {
"Description": "Max bid price of spot instances",
"Type": "String",
"Default": ".06"
},
"DeployS3Bucket": {
"Description": "The S3 Bucket where deploy files are stored",
"Type": "String",
"Default": "ApplicationBucket"
},
"DeployWebS3Key": {
"Description": "The zip file that holds the website",
"Type": "String",
"Default": "Application.zip"
},
"DNSHostedZone": {
"Type": "String",
"Default": "example.com.",
"AllowedPattern": "^[\\w\\.]*\\.$",
"ConstraintDescription": "DNSDomain must end with '.'"
},
"DNSSubDomain": {
"Type": "String",
"Default": "yoursubdomain"
}
},
"Mappings": {
"RegionToAMIMap": {
"us-east-1": {
"AMI": "ami-1234567"
}
}
},
"Resources": {
"IAMUser": {
"Type": "AWS::IAM::User",
"Properties": {
"Path": "/",
"Policies": [{
"PolicyName": "webuser",
"PolicyDocument": {
"Statement": [{
"Sid": "Stmt1353842250430",
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::HelgaDogWeb*/*"
]
}, {
"Sid": "Stmt1353842327065",
"Action": [
"cloudformation:DescribeStackResource"
],
"Effect": "Allow",
"Resource": [
"*"
]
}
]
}
}
]
}
},
"IAMUserAccessKey": {
"Type": "AWS::IAM::AccessKey",
"Properties": {
"UserName": {
"Ref": "IAMUser"
}
}
},
"WebSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Enable Access From Elastic Load Balancer.",
"SecurityGroupIngress": [{
"IpProtocol": "tcp",
"FromPort": "443",
"ToPort": "443",
"SourceSecurityGroupOwnerId": {
"Fn::GetAtt": [
"WebLoadBalancer",
"SourceSecurityGroup.OwnerAlias"
]
},
"SourceSecurityGroupName": {
"Fn::GetAtt": [
"WebLoadBalancer",
"SourceSecurityGroup.GroupName"
]
}
}, {
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"SourceSecurityGroupOwnerId": {
"Fn::GetAtt": [
"WebLoadBalancer",
"SourceSecurityGroup.OwnerAlias"
]
},
"SourceSecurityGroupName": {
"Fn::GetAtt": [
"WebLoadBalancer",
"SourceSecurityGroup.GroupName"
]
}
}
]
}
},
"WebLoadBalancer": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"Listeners": [{
"InstancePort": "443",
"InstanceProtocol": "HTTPS",
"LoadBalancerPort": "443",
"Protocol": "HTTPS",
"SSLCertificateId": "arn:aws:iam::123456789101:server-certificate/example"
}
],
"AvailabilityZones": {
"Fn::GetAZs": ""
},
"HealthCheck": {
"HealthyThreshold": "3",
"Interval": "30",
"Target": "HTTP:80/healthcheck.aspx",
"Timeout": 8,
"UnhealthyThreshold": "2"
}
}
},
"WebAsSpotLaunchConfiguration": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Metadata": {
"AWS::CloudFormation::Init": {
"config": {
"sources": {
"C:\\inetpub\\wwwroot": {
"Fn::Join": [
"/",
[
"http://s3.amazonaws.com", {
"Ref": "DeployS3Bucket"
}, {
"Ref": "DeployWebS3Key"
}
]
]
}
},
"commands": {
"1-set-appPool-identity": {
"command": "C:\\Windows\\System32\\inetsrv\\appcmd set config /section:applicationPools /[name='DefaultAppPool'].processModel.identityType:LocalSystem",
"waitAfterCompletion": "0"
},
"2-add-http-binding": {
"command": "C:\\Windows\\System32\\inetsrv\\appcmd set site /site.name:\"Default Web Site\" /+bindings.[protocol='http',bindingInformation='*:80:']",
"waitAfterCompletion": "0"
}
}
}
},
"AWS::CloudFormation::Authentication": {
"S3AccessCreds": {
"type": "S3",
"accessKeyId": {
"Ref": "IAMUserAccessKey"
},
"secretKey": {
"Fn::GetAtt": [
"IAMUserAccessKey",
"SecretAccessKey"
]
},
"buckets": [{
"Ref": "DeployS3Bucket"
}
]
}
}
},
"Properties": {
"KeyName": {
"Ref": "KeyName"
},
"ImageId": {
"Fn::FindInMap": [
"RegionToAMIMap", {
"Ref": "AWS::Region"
},
"AMI"
]
},
"IamInstanceProfile": {
"Ref": "IamInstanceProfile"
},
"SecurityGroups": [{
"Ref": "WebSecurityGroup"
}
],
"InstanceType": {
"Ref": "InstanceType"
},
"SpotPrice": {
"Ref": "SpotPriceBid"
},
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"<script>\n",
"\"C:\\Program Files (x86)\\Amazon\\cfn-bootstrap\\cfn-init.exe\" -v -s ", {
"Ref": "AWS::StackName"
},
" -r WebAsSpotLaunchConfiguration ",
" --access-key ", {
"Ref": "IAMUserAccessKey"
},
" --secret-key ", {
"Fn::GetAtt": [
"IAMUserAccessKey",
"SecretAccessKey"
]
},
"\n",
"</script>"
]
]
}
}
}
},
"WebAsSpotGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"AvailabilityZones": {
"Fn::GetAZs": ""
},
"HealthCheckGracePeriod": "120",
"HealthCheckType": "EC2",
"LaunchConfigurationName": {
"Ref": "WebAsSpotLaunchConfiguration"
},
"LoadBalancerNames": [{
"Ref": "WebLoadBalancer"
}
],
"MaxSize": "20",
"MinSize": "1",
"DesiredCapacity": "1"
}
},
"WebAsSpotScaleUpPolicy": {
"Type": "AWS::AutoScaling::ScalingPolicy",
"Properties": {
"AdjustmentType": "PercentChangeInCapacity",
"AutoScalingGroupName": {
"Ref": "WebAsSpotGroup"
},
"Cooldown": "420",
"ScalingAdjustment": "200"
}
},
"WebAsSpotScaleDownPolicy": {
"Type": "AWS::AutoScaling::ScalingPolicy",
"Properties": {
"AdjustmentType": "ChangeInCapacity",
"AutoScalingGroupName": {
"Ref": "WebAsSpotGroup"
},
"Cooldown": "60",
"ScalingAdjustment": "-1"
}
},
"WebAsSpotScaleUpAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"MetricName": "CPUUtilization",
"Namespace": "AWS/EC2",
"Statistic": "Average",
"Period": "60",
"EvaluationPeriods": "1",
"Threshold": "75",
"AlarmActions": [{
"Ref": "WebAsSpotScaleUpPolicy"
}
],
"Dimensions": [{
"Name": "AutoScalingGroupName",
"Value": {
"Ref": "WebAsSpotGroup"
}
}
],
"ComparisonOperator": "GreaterThanThreshold"
}
},
"WebAsSpotScaleDownAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"MetricName": "CPUUtilization",
"Namespace": "AWS/EC2",
"Statistic": "Average",
"Period": "60",
"EvaluationPeriods": "2",
"Threshold": "50",
"AlarmActions": [{
"Ref": "WebAsSpotScaleDownPolicy"
}
],
"Dimensions": [{
"Name": "AutoScalingGroupName",
"Value": {
"Ref": "WebAsSpotGroup"
}
}
],
"ComparisonOperator": "LessThanThreshold"
}
},
"DNSRecord": {
"Type": "AWS::Route53::RecordSet",
"Properties": {
"HostedZoneName": {
"Ref": "DNSHostedZone"
},
"Comment": "VPN Host. Created by Cloud Formation.",
"Name": {
"Fn::Join": [
".",
[{
"Ref": "DNSSubDomain"
}, {
"Ref": "DNSHostedZone"
}
]
]
},
"Type": "CNAME",
"TTL": "150",
"ResourceRecords": [{
"Fn::GetAtt": [
"WebLoadBalancer",
"CanonicalHostedZoneName"
]
}
]
},
"DependsOn": "WebLoadBalancer"
}
},
"Outputs": {}
}
I havent tried it myself, but this post, on the AWS site, Using Amazon CloudFront with ASP.NET Apps maybe somewhere to start.

Categories