Why is my JSON not camelCase? - json.net

I'm trying to output Json, with Json.net, by building up a dynamic then calling JsonConvert.Serialize().
The problem is that my _camelCase contract resolver is not respected, and the output is not camel case.
private JsonSerializerSettings _camelCase = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var myObj = new { Prop = "val"};
var myObj2 = new { Prop = "val" };
var objOut = JsonConvert.SerializeObject(myObj, _camelCase);
// {"prop":"val"}
// No problem
// now, a list
var list = new List<object> { myObj, myObj2 };
var listOut = JsonConvert.SerializeObject(list, _camelCase);
// [{"prop":"val"},{"prop":"val"}]
// no problem
// now, put my list in a dynamic
dynamic myDynamic = new JObject();
myDynamic.List = JArray.FromObject(list);
var dynamicOut = JsonConvert.SerializeObject(myDynamic, _camelCase);
// {"List":[{"Prop":"val"},{"Prop":"val"}]}
// PROBLEM! _camelCase is not respected
Can anyone tell me what is going on here?

Ok in case this can be useful for anyone... The serializer settings that count are not those supplied to JsonConvert.Serialize(), but those used for the call JArray.FromObject(). So I needed to create a serializer with the contract resolver...
private JsonSerializerSettings _camelCase = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
private JsonSerializer _camelCaseSerializer = JsonSerializer.Create(_camelCase);
...then use it for FromObject()...
myDynamic.List = JArray.FromObject(list, _camelCaseSerializer );
I could also have changed the default settings like this...
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
... but I lack the courage :-)

Related

Is there a utility to serialise an object as HTTP content type "application/x-www-form-urlencoded"?

I've never had to do this before, because it's always only been an actual form that I've posted as that content type, but recently I had to post three variables like that, and I resorted to a sordid concatenation with & and =:
var content = new StringContent("grant_type=password&username=" + username + "&password=" + password.ToClearString(), Encoding.UTF8,
"application/x-www-form-urlencoded");
I'm sure there must be a utility method that would do that, and do it better, with any necessary encoding. What would that be?
If this is a POCO and just using the Newtonsoft library, you can use this as well:
public static class FormUrlEncodedContentExtension
{
public static FormUrlEncodedContent ToFormUrlEncodedContent(this object obj)
{
var json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
var keyValues = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
var content = new FormUrlEncodedContent(keyValues);
return content;
}
}
And a sample usage would be:
var myObject = new MyObject {Grant_Type = "TypeA", Username = "Hello", Password = "World"};
var request = new HttpRequestMessage(HttpMethod.Post, "/path/to/post/to")
{
Content = myObject.ToFormUrlEncodedContent()
};
var client = new HttpClient {BaseAddress = new Uri("http://www.mywebsite.com")};
var response = await client.SendAsync(request);
Use reflection to get the property names and values and then use them to create a System.Net.Http.FormUrlEncodedContent
public static class FormUrlEncodedContentExtension {
public static FormUrlEncodedContent ToFormUrlEncodedContent(this object obj) {
var nameValueCollection = obj.GetType()
.GetProperties()
.ToDictionary(p => p.Name, p => (p.GetValue(obj) ?? "").ToString());
var content = new FormUrlEncodedContent(nameValueCollection);
return content;
}
}
From there it is a simple matter of calling the extension method on an object to convert it to a FormUrlEncodedContent
var model = new MyModel {
grant_type = "...",
username = "...",
password = "..."
};
var content = model.ToFormUrlEncodedContent();
You should be able to use string interpolation for that. Something like:
var content = new StringContent($"grant_type=password&username={username}&password={password}", Encoding.UTF8, "application/x-www-form-urlencoded");
Or wrap this inside a helper/factory method:
public static class StringContentFactory
{
public static StringContent Build(string username, string password)
{
return new StringContent($"grant_type=password&username={username}&password={password}", Encoding.UTF8, "application/x-www-form-urlencoded");
}
}

.net Querying a Global Secondary Index in DynamoDB via DynamoDBContext

I have a dynamoDB table with a schema as follows:
var request = new CreateTableRequest
{
TableName = tableName,
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement("CompanyId", KeyType.HASH),
new KeySchemaElement("Timestamp", KeyType.RANGE)
},
AttributeDefinitions = new List<AttributeDefinition>
{
new AttributeDefinition("CompanyId", ScalarAttributeType.S),
new AttributeDefinition("Timestamp", ScalarAttributeType.N),
new AttributeDefinition("UserId", ScalarAttributeType.S)
},
GlobalSecondaryIndexes = new List<GlobalSecondaryIndex>
{
new GlobalSecondaryIndex
{
IndexName = "UserIndex",
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement("UserId", KeyType.HASH),
new KeySchemaElement("Timestamp", KeyType.RANGE)
},
Projection = new Projection {ProjectionType = "ALL"},
ProvisionedThroughput = new ProvisionedThroughput(5, 6)
}
},
ProvisionedThroughput = new ProvisionedThroughput(5, 6)
};
I can query the primary key successfully as follows:
var client = new AmazonDynamoDBClient();
using (var context = new DynamoDBContext(client))
{
var sortKeyValues = new List<object>{minTimestamp};
result = await context.QueryAsync<AuditLogEntry>(companyId, QueryOperator.GreaterThanOrEqual, sortKeyValues,
new DynamoDBOperationConfig {OverrideTableName = TableName}).GetRemainingAsync();
}
And I can query the global secondary index without any constraint on the range key as follows:
var client = new AmazonDynamoDBClient();
using (var context = new DynamoDBContext(client))
{
result = await context.QueryAsync<AuditLogEntry>(userId, new DynamoDBOperationConfig {OverrideTableName = TableName, IndexName = indexName})
.GetRemainingAsync();
}
But when I try to query the index with a range key constraint:
var client = new AmazonDynamoDBClient();
using (var context = new DynamoDBContext(client))
{
var sortKeyValues = new List<object> {minTimestamp};
result = await context.QueryAsync<AuditLogEntry>(userId, QueryOperator.GreaterThan, sortKeyValues, new DynamoDBOperationConfig {OverrideTableName = TableName, IndexName = indexName}).GetRemainingAsync();
}
I get the following error:
Exception thrown: 'System.InvalidOperationException' in AWSSDK.DynamoDBv2.dll
Additional information: Local Secondary Index range key conditions are used but no index could be inferred from model. Specified index name = UserIndex
Googling this error hasn't thrown any light on the issue. The reference to Local Secondary Index has me confused because I'm using a Global index, but I just can't see what's wrong with my code.
I've been able to get the query working by querying directly on the AmazonDynamoDBClient rather than using DynamoDBContext, but I'd really like to understand what I'm doing wrong and be able to use DynamoDBContext.
Any ideas would be appreciated.
In your model definition for AuditLogEntry you need to decorate properties that are part of the global secondary index with attributes - [DynamoDBGlobalSecondaryIndexRangeKey] and or [DynamoDBGlobalSecondaryIndexHashKey]. Example below.
public class AuditLogEntry {
// other properties ...
[DynamoDBProperty("UserId")]
[DynamoDBGlobalSecondaryIndexHashKey("UserIndex")]
public string UserId { get; set; }
}

Mocking Asp.net FriendlyUrls

Has anyone mocked FriendlyUrls for unit testing?
I am writing a test that needs to mock asp.net FriendlyUrls. The call I need to mock specifically is Request.GetFriendlyUrlSegments(). I am using MS Fakes.
Here is my test so far:
// Arrange
var httpContext = TestHelper.StubHtppContext("", "http://localhost/content.aspx/area/controller/action/OtherRouteValue", "");
var httpContextBase = new HttpContextWrapper(httpContext);
RouteTable.Routes.MapRoute(
"RouteName",
"Area/{controller}/{action}/{id}/{OtherRoute}",
new {action = "Index", id = UrlParameter.Optional, OtherRoute = UrlParameter.Optional});
RouteTable.Routes.EnableFriendlyUrls();
var segments = new List<String> {"Controller", "Action", "Id", "OtherRoute"};
using (ShimsContext.Create())
{
ShimHttpContext.CurrentGet = () => httpContext;
ShimFriendlyUrl.SegmentsGet = () => segments;
// Act
RouteData result = MvcUtility.GetRouteValuesFromUrl();
// Assert
Assert.IsNotNull(result, "Expected RouteData to be created.");
}
}
The relevant Part of the system under test:
public static RouteData GetRouteValuesFromUrl()
{
var request = System.Web.HttpContext.Current.Request;
var segments = request.GetFriendlyUrlSegments();
//Other code
}
I would expect for segments to use my shim get and return my list of segments.
My code works when I run it in the web context, I just need to find a way to unit test it and the first step is mocking shim/stub this request.GetFriendlyUrlSegments() call.
Based on slaks suggestion, the right data to fake here is the Request.RequestContext.RouteData. It needs a DataToken with a "FriendlyUrlSegments" key.
The corrected and working test:
var httpContext = TestHelper.StubHtppContext("", "http://localhost/content.aspx/area/controller/action/OtherRouteValue", "");
var httpContextBase = new HttpContextWrapper(httpContext);
RouteTable.Routes.MapRoute(
"RouteName",
"Area/{controller}/{action}/{id}/{OtherRoute}",
new {action = "Index", id = UrlParameter.Optional, OtherRoute = UrlParameter.Optional});
RouteTable.Routes.EnableFriendlyUrls();
var segments = new List<String> {"Controller", "Action", "Id", "OtherRoute"};
var requestContext = new StubRequestContext(httpContextBase, new RouteData());
var mockedRouteData = new RouteData();
mockedRouteData.DataTokens.Add("FriendlyUrlSegments", segments);
requestContext.RouteDataGet = () => mockedRouteData;
using (ShimsContext.Create())
{
ShimHttpContext.CurrentGet = () => httpContext;
ShimHttpRequest.AllInstances.RequestContextGet = request => requestContext;
// Act
RouteData result = MvcUtility.GetRouteValuesFromUrl();
// Assert
Assert.IsNotNull(result, "Expected RouteData to be created.");

Looping through an arraylist sourced from an XML file

I am reading in an XML file that is shown in the attached image. I'm reading it in using URLRequest, which works properly. The next thing I'd like to do is to populate an arraylist with all of the "project" nodes. I'm converting the XML to an array, but the source is showing the project as being in the [0] node and the arraylist's length is 1.
What's the proper way to do this so I can loop through all the projects in the arraylist?
private var xmlParameters:XML
private var xmlStoryMap:XMLList;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
var params:Object;
var xmlLoader:URLLoader = new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE, xmlloader_onComplete_Handler);
xmlLoader.addEventListener(IOErrorEvent.IO_ERROR,IOError_handler);
xmlLoader.load(new URLRequest("myXML.xml"));
}
protected function xmlloader_onComplete_Handler(event:Event):void
{
var loader:URLLoader = URLLoader(event.target)
xmlParameters = new XML(loader.data);
xmlStoryMap = xmlParameters.projects;
initializeMap();
}
protected function initializeMap():void
{
var testlist:ArrayList = new ArrayList();
testlist.source = convertXMLtoArray(xmlStoryMap.project);
}
private function convertXMLtoArray(file:String):Array
{
var xml:XMLDocument = new XMLDocument(file);
var decoder:SimpleXMLDecoder = new SimpleXMLDecoder;
var data:Object = decoder.decodeXML(xml);
var array:Array = ArrayUtil.toArray(data);
return array;
}
If you don't want to have a loop issue, use this instead
protected function xmlloader_onComplete_Handler(event:Event):void
{
var loader:URLLoader = URLLoader(event.target)
var xmlString:String = loader.data;
initializeMap(xmlString);
}
protected function initializeMap(xmlString:String):void
{
var testlist:ArrayList = new ArrayList();
testlist.source = convertXMLtoArray(xmlString);
}
private function convertXMLtoArray(xmlString:String):Array
{
var xmlDoc:XMLDocument = new XMLDocument(xmlString);
var decoder:SimpleXMLDecoder = new SimpleXMLDecoder();
var data:Object = decoder.decodeXML(xmlDoc);
return ArrayUtil.toArray(data.storymap.projects.project);
}
For looping through the projects,
for each(var projectXML:XML in xmlParameters.projects.project)
{
// Do operation
}

Flex - Dynamically add a property to an object based on a string value

I create a new object. My new object will always have a labelField because it has to be added to a dataProvider in a ComboBox. The problem is my next property. Each object in the dataProvider has a dataField property that has a string value [eg: 'code' or 'isoCode']. What I want to be able to do is this:
var myObject:Object = new Object; // functional
var myOtherObject:Object = new Object; // functional
myOtherObject[dataField] = "code"; // functional
myObject[labelField] = "Hi"; // functional
myObject[myOtherObject[dataField].value] = "ALL"; // not functional
Any help would be appreciated.
Try this:
var myObject:Object = new Object();
var myOtherObject:Object = new Object();
myOtherObject.dataField = "code";
myObject.labelField = "Hi";
myObject[myOtherObject.dataField] = "ALL";

Resources