Asp.net core web API DeserilizationObject not working - asp.net

I am using ASP.net core web api and angular 10. When I make a post request from angular project, it is passing the correct json object. It hit the POST method on my api side. Than I try to deserializeObject but it is throwing error.
ERROR:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'The best overloaded method match for 'Newtonsoft.Json.JsonConvert.DeserializeObject<API.ViewModel.EmpDepViewMode>(string)' has some invalid arguments'
JSON I am passing
{
"Employees": [
{
"Name": "John Doe",
"yearlySalary": "50000",
"numberOfPayCheck": 26
}
],
"Dependents": [
{
"Type": 0,
"Name": "Maria Smith"
}
]
}
EmpDepViewModel:
public class EmpDepViewMode
{
public List<Employee> Employees { get; set; } = new List<Employee>();
public List<Dependent> Dependents { get; set; } = new List<Dependent>();
}
Employee class:
public class Employee
{
public string Name { get; set; }
public int yearlySalary { get; set; }
public int numberOfPayCheck { get; set; }
}
Dependent class
public class Dependent
{
public string Name { get; set; }
public DependentType Type { get; set; }
}
POST Method
public IActionResult Post(dynamic employeeDependent1)
{
EmpDepViewMode employeeDependent = JsonConvert.DeserializeObject<EmpDepViewMode>(employeeDependent1);
return Ok(employeeDependent )
}
Any help would be appreciated

You have to fix action, you are trying to deserialize data the second time, since it was deserialized already automaticaly. And it doesn' t make much sense to make it dynamic since you use already EmpDepViewMode
public IActionResult Post(EmpDepViewMode employeeDependent)
{
return Ok(employeeDependent )
}

Related

how I can send 2 object to my API (ASP.NET)?

I have a problem that I cannot solve. I would like to transmit the deck created by the user to my API but the problem is that the card and the deck are two different entities in my database that's why I need to pass the information of the deck and the list card to my API to add them to my database.
my entity:
public class Card
{
public Card() {
this.Decks = new HashSet<Deck>();
}
public int Id { get; set; }
[Column(TypeName = "json")]
public string Content { get; set; }
[NotMapped]
public virtual ICollection<Deck> Decks { get; set; }
}
public class Deck
{
public Deck() {
this.Cards = new HashSet<Card>();
}
public int Id { get; set; }
public string Name { get; set; }
[DataType(DataType.Date)]
public DateTime CreateAt { get; set; }
public User User { get; set; }
[NotMapped]
public virtual ICollection<Card> Cards { get; set; }
}
public class Join
{
public int DeckId { get; set; }
public Deck Deck { get; set; }
public int CardId { get; set; }
public Card Card { get; set; }
}
my API:
[HttpPost]
public void Add ([FromBody] JsonObject request) {
}
the JSON:
{
"Deck":{
"Name": "",
"CreateAt": "2007-07-15",
"User": "null"
},
"Crads":[
{"content": {}},
{"content": {}}
]
}
Response:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|99e854f-4f63859a690203b6.",
"errors": {
"$.Deck.User": [
"The JSON value could not be converted to MTG_Deck.Models.User. Path: $.Deck.User | LineNumber: 4 | BytePositionInLine: 22."
]
}
}
I think it is better that in your API you receive a DTO that encapsulates the two classes you need (Deck and Card). Inside your method then take the information you need and save the entities correctly in the database.
public class AddDeckAndCardDTO
{
public Deck Deck { get; set; }
public List<Card> Card { get; set; }
}
And the method Add in the API
[HttpPost]
public void Add ([FromBody] AddDeckAndCardDTO request)
{
var card = request.Card;
var deck = request.Deck
// the code to mapped entities
// the code to save your entities
}

Parsing Json Data With Flurl and ASP.net Core

not really sure if I'm asking this in the correct manner. But I am doing a project for my university with CRM systems and API's.
Now I found Flurl to help me do my HTTP request. and it works great until I try and do a get all accounts to my free developer account to salesforce (i added some test accounts). The JSON I receive is this:
{
"objectDescribe": {
"activateable": false,
"createable": true,
"custom": false,
"customSetting": false,
"deletable": true,
"deprecatedAndHidden": false,
"feedEnabled": true,
"hasSubtypes": false,
"isSubtype": false,
"keyPrefix": "001",
"label": "Account",
"labelPlural": "Accounts",
"layoutable": true,
"mergeable": true,
"mruEnabled": true,
"name": "Account",
"queryable": true,
"replicateable": true,
"retrieveable": true,
"searchable": true,
"triggerable": true,
"undeletable": true,
"updateable": true,
"urls": {
"compactLayouts": "/services/data/v39.0/sobjects/Account/describe/compactLayouts",
"rowTemplate": "/services/data/v39.0/sobjects/Account/{ID}",
"approvalLayouts": "/services/data/v39.0/sobjects/Account/describe/approvalLayouts",
"defaultValues": "/services/data/v39.0/sobjects/Account/defaultValues?recordTypeId&fields",
"listviews": "/services/data/v39.0/sobjects/Account/listviews",
"describe": "/services/data/v39.0/sobjects/Account/describe",
"quickActions": "/services/data/v39.0/sobjects/Account/quickActions",
"layouts": "/services/data/v39.0/sobjects/Account/describe/layouts",
"sobject": "/services/data/v39.0/sobjects/Account"
}
},
"recentItems": [
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it9T3AAI"
},
"Id": "0015800000it9T3AAI",
"Name": "Test 5"
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it8eAAAQ"
},
"Id": "0015800000it8eAAAQ",
"Name": "Test 4"
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it8dbAAA"
},
"Id": "0015800000it8dbAAA",
"Name": "Test 3"
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it8dHAAQ"
},
"Id": "0015800000it8dHAAQ",
"Name": "Test 2"
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it8ciAAA"
},
"Id": "0015800000it8ciAAA",
"Name": "Test 1"
}
]
}
and the error I receive is the following:
Request to https://eu6.salesforce.com/services/data/v39.0/sobjects/Account/ failed.
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[InHollandCRMAPI.Models.AccountItem]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'objectDescribe', line 1, position 18.
I also found this link on here:
Parsing from json to object using FLURL
but I can't seem to recreate this with my model:
public class AccountItem : ICRMItem
{
public Describe[] ObjectDescribe { get; set; }
public List<Recent> recentItems { get; set; }
public class Recent
{
public Attributes[] Attributes { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
public class Describe
{
public bool activateable { get; set; }
public bool createable { get; set; }
public bool custom { get; set; }
public bool customSetting { get; set; }
public bool deletable { get; set; }
public bool deprecatedAndHidden { get; set; }
public bool feedEnabled { get; set; }
public bool hasSubtypes { get; set; }
public bool isSubtype { get; set; }
public string keyPrefix { get; set; }
public string label { get; set; }
public string labelPlural { get; set; }
public bool layoutable { get; set; }
public bool mergeable { get; set; }
public bool mruEnabled { get; set; }
public string name { get; set; }
public bool queryable { get; set; }
public bool replicateable { get; set; }
public bool retrieveable { get; set; }
public bool searchable { get; set; }
public bool triggerable { get; set; }
public bool undeletable { get; set; }
public bool updateable { get; set; }
public Urls[] urls { get; set; }
}
}
and at last this is how de Deserialize is in my code
response = request.GetAsync();
responseData = await response.ReceiveJson<T>().ConfigureAwait(true);
Edit my controller class where the requests come in:
[HttpGet("{CRM}")]
public IEnumerable<ICRMItem> Get(string CRM)
{
if(CRM == "SalesForce")
{
ICRMService AccountGetAll = new AccountService();
var Account = AccountGetAll.With<AccountItem>().GetAll().ResponseData();
return Account;
}
}
After #Todd Menier his changes
as my response in Todd's message shamefully it didn't do the trick. and i still get this exception message.
Request to https://eu6.salesforce.com/services/data/v39.0/sobjects/Account/ ailed. Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type
'System.Collections.Generic.IEnumerable`1[InHollandCRMAPI.Models.AccountItem]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>)
that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'objectDescribe', line 1, position 18.
Edit
Todd Menier asked me for the path my code takes so here it is:
After I do my call it comes in my controller
ICRMService AccountGetAll = new AccountService();
var Account = AccountGetAll.With<AccountItem>().GetAll().ResponseData();
return Account;
Where after it goes into my service:
public ICRMServiceWithResource<T> With<T>(bool beta = false) where T : ICRMItem
{
var Uri = "https://eu6.salesforce.com/services/data/v39.0/";
return new SalesForceServiceWithResource<T>()
{
Resource = Resources.Resources.GetResource<T>(),
Uri = Uri
};
}
then it gets the Recources
public class Resources
{
public const string Accounts = "sobjects/Account/";
public static string GetResource<T>() where T : ICRMItem
{
var type = typeof(T);
if (type == typeof(AccountItem)) return Accounts;
and it gets into my GetAll function
public ICRMResponse<IEnumerable<T>> GetAll()
{
return Get<IEnumerable<T>>();
}
as you see it goes to a get function
private ICRMResponse<TOut> Get<TOut>(string id = "")
{
return DoRequest<TOut>(Resource + id, "GET", null).Result;
}
from where it goes into the DoRequest:
public async Task<ICRMResponse<T>> DoRequest<T>(string url, string method, object body)
{
ICRMResponse<T> result;
try
{
GetCRM(AppConfig.Key);
var request = Authorise(url);
Task<HttpResponseMessage> response;
T responseData;
switch (method.ToLower())
{
case "post":
if (body == null)
{
throw new ArgumentNullException("body");
}
response = request.PostJsonAsync(body);
responseData = await response.ReceiveJson<T>().ConfigureAwait(false);
break;
case "get":
response = request.GetAsync();
responseData = await response.ReceiveJson<T>().ConfigureAwait(true);
break;
from where it breaks and shows the message as state before
i'll check back around 16:00 GMT+1 or else Tuesday morning hope i gave you everything you needed
In your C# model, urls is an array, but it is not an array in the JSON representation; it is an object.
You didn't post the definition of your Urls class, but I'm going to guess it looks like this:
public class Urls
{
public string compactLayouts { get; set; }
public string rowTemplate { get; set; }
public string approvalLayouts { get; set; }
public string defaultValues { get; set; }
public string listviews { get; set; }
public string describe { get; set; }
public string quickActions { get; set; }
public string layouts { get; set; }
public string sobject { get; set; }
}
The JSON is returning a single object that looks like this, not a collection of them. So, in your Describe class, just drop the array and define it like this:
public Urls urls { get; set; }
UPDATE:
I didn't see this at first but there's a similar problem with objectDescribe and attributes. Those aren't arrays either, so don't define them that way in your C# model. Here's a summary of all changes:
public class AccountItem : ICRMItem
{
public Describe ObjectDescribe { get; set; }
...
public class Recent
{
public Attributes Attributes { get; set; }
...
}
public class Describe
{
...
public Urls urls { get; set; }
}
}
Soo, I just fixed the Error. Was trying to get a List of all Accounts. but salesforce already Lists (part) the Accounts for you.
The Issue was IEnumerable in the GetAll() function (wich works great for most CRM systems) but if you wanna get this done you'd need to change the IEnumerable<T> to just T and that would be the quick fix for SalesForce
The Next step for me is to generate a List of accounts with all account info (as most GetAll's work with CRM API's).
TL;DR
public ICRMResponse<IEnumerable<T>> GetAll()
{
return Get<IEnumerable<T>>();
}
should be
public ICRMResponse<T> GetAll() //Technicly isn't a GetAll But a Get
{
return DoRequest<T>(Resource, "GET", null).Result;
}
This is a Fix to this post not a fix to my eventual wish but I'll close this topic because else we will go off topic

ASP.NET Web API with Many-Many relationships

I'm having some trouble with ASP.NET Web API with many-many relationships between models. Here are my models (which I've simplified for brevity):
public class Model1
{
public int Model1ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Model2> Model2s{ get; set; }
public string Self
{
get
{
return string.Format(CultureInfo.CurrentCulture,
"api/model1/{0}", this.Model1ID);
}
set { }
}
}
public class Model2
{
public int Model2ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Model1> Model1s{ get; set; }
public string Self
{
get
{
return string.Format(CultureInfo.CurrentCulture,
"api/model2/{0}", this.Model2ID);
}
set { }
}
}
and my relevant Model1 API controller excerpt:
public class Model1sController : ApiController
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: api/Model1s
public IQueryable<Model1> GetModel1s()
{
return db.Model1s;
}
...
}
When I navigate to /api/model1s I get a long JSON nested error, here is the innermost Exception message.
There is already an open DataReader associated with this Command which must be closed first.
What I'm trying to achieve is output like this, but I cannot figure out how to get it working.
[{
"Model1ID": 1,
"Name": "Some model 2 name",
"Model2s": [{
"Model2ID": 1,
"Name": "Another model 2 name"
}, {
"Model2ID": 2,
"Name": "Some model 2 name"
}]
}, {
"Model1ID": 2,
"Name": "Another model 1 name",
"Model2s": [{
"Model2ID": 2,
"Name": "Some model 2 name"
}]
}]
What you need is called and associative entity, some devs call them a lookup table. An associative entity will hold the “association” between two other entities. In your case I believe that there is a scaffolding engine that will build the database tables for you based on the classes you create. Someone else may be able to speak to how the scaffolding engine works.
I would create a class called “TvProgramming” and give it properties Name, Id, Host_Id, Host_Name, and List. Now with this set up you can have as many hosts and as many tv shows as you want and still create unique programming schedules.
Adjust the tv show and host objects so that they only have properties that are unique to themselves ie a TvShow will have an name, id, and maybe a length. A host may have name, id, network, and location info however notice that the host object and tv show object have no knowledge of the other, only the associative entity holds knowledge of the relationship between them.
At the end of the day what your api should return is a set of TvProgramming objects that contain the hosts and for each host a list of tv shows… here is an quick example of the class structure I’m talking about, you’ll have to tweak it a bit to fit your needs but it should get started.
namespace YourProjectName.Models
{
public class TvShow
{
public int id { get; set; }
public string name { get; set; }
public TimeSpan length { get; set; }
public string rating { }
public TvShow() { }
}
public class Host
{
public int id { get; set; }
public string name { get; set; }
public string network { get; set; }
public string city { get; set; }
public string state { get; set; }
public string zip { get; set; }
public string country { get; set; }
public Host() { }
}
public class TvProgramming
{
public int id { get; set; }
public string name { get; set; }
public int host_Id { get; set; }
public string host_Name { get; set; }
public List<TvShow> shows { get; set; }
public TvProgramming()
{
this.shows = new List<TvShow>();
}
}
}
As a way of possibly preventing the error you are getting, try modifying your Controller code like this:
public class Model1sController : ApiController
{
// GET: api/Model1s
public IQueryable<Model1> GetModel1s()
{
using (var db = new ApplicationDbContext())
{
return db.Model1s;
}
}
}

Using DTO's with OData & Web API

Using Web API and OData, I have a service which exposes Data Transfer Objects instead of the Entity Framework entities.
I use AutoMapper to transform the EF Entities into their DTO counter parts using ProjectTo():
public class SalesOrdersController : ODataController
{
private DbContext _DbContext;
public SalesOrdersController(DbContext context)
{
_DbContext = context;
}
[EnableQuery]
public IQueryable<SalesOrderDto> Get(ODataQueryOptions<SalesOrderDto> queryOptions)
{
return _DbContext.SalesOrders.ProjectTo<SalesOrderDto>(AutoMapperConfig.Config);
}
[EnableQuery]
public IQueryable<SalesOrderDto> Get([FromODataUri] string key, ODataQueryOptions<SalesOrderDto> queryOptions)
{
return _DbContext.SalesOrders.Where(so => so.SalesOrderNumber == key)
.ProjectTo<SalesOrderDto>(AutoMapperConfig.Config);
}
}
AutoMapper (V4.2.1) is configured as follows, note the ExplicitExpansion() which prevents serialisation auto expanding navigation properties when they are not requested:
cfg.CreateMap<SalesOrderHeader, SalesOrderDto>()
.ForMember(dest => dest.SalesOrderLines, opt => opt.ExplicitExpansion());
cfg.CreateMap<SalesOrderLine, SalesOrderLineDto>()
.ForMember(dest => dest.MasterStockRecord, opt => opt.ExplicitExpansion())
.ForMember(dest => dest.SalesOrderHeader, opt => opt.ExplicitExpansion());
ExplicitExpansion() then creates a new problem where the following request throws an error:
/odatademo/SalesOrders('123456')?$expand=SalesOrderLines
The query specified in the URI is not valid. The specified type member 'SalesOrderLines' is not supported in LINQ to Entities
The navigation property SalesOrderLines is unknown to EF so this error is pretty much what I expected to happen. The question is, how do I handle this type of request?
The ProjectTo() method does have an overload that allows me to pass in an array of properties that require expansion, I found & modified the extension method ToNavigationPropertyArray to try and parse the request into a string array:
[EnableQuery]
public IQueryable<SalesOrderDto> Get([FromODataUri] string key, ODataQueryOptions<SalesOrderDto> queryOptions)
{
return _DbContext.SalesOrders.Where(so => so.SalesOrderNumber == key)
.ProjectTo<SalesOrderDto>(AutoMapperConfig.Config, null, queryOptions.ToNavigationPropertyArray());
}
public static string[] ToNavigationPropertyArray(this ODataQueryOptions source)
{
if (source == null) { return new string[]{}; }
var expandProperties = string.IsNullOrWhiteSpace(source.SelectExpand?.RawExpand) ? new List<string>().ToArray() : source.SelectExpand.RawExpand.Split(',');
for (var expandIndex = 0; expandIndex < expandProperties.Length; expandIndex++)
{
// Need to transform the odata syntax for expanding properties to something EF will understand:
// OData may pass something in this form: "SalesOrderLines($expand=MasterStockRecord)";
// But EF wants it like this: "SalesOrderLines.MasterStockRecord";
expandProperties[expandIndex] = expandProperties[expandIndex].Replace(" ", "");
expandProperties[expandIndex] = expandProperties[expandIndex].Replace("($expand=", ".");
expandProperties[expandIndex] = expandProperties[expandIndex].Replace(")", "");
}
var selectProperties = source.SelectExpand == null || string.IsNullOrWhiteSpace(source.SelectExpand.RawSelect) ? new List<string>().ToArray() : source.SelectExpand.RawSelect.Split(',');
//Now do the same for Select (incomplete)
var propertiesToExpand = expandProperties.Union(selectProperties).ToArray();
return propertiesToExpand;
}
This works for expand, so now I can handle a request like the following:
/odatademo/SalesOrders('123456')?$expand=SalesOrderLines
or a more complicated request like:
/odatademo/SalesOrders('123456')?$expand=SalesOrderLines($expand=MasterStockRecord)
However, more complicated request that try to combine $select with $expand will fail:
/odatademo/SalesOrders('123456')?$expand=SalesOrderLines($select=OrderQuantity)
Sequence contains no elements
So, the question is: am I approaching this the right way?
It feels very smelly that I would have to write something to parse and transform the ODataQueryOptions into something EF can understand.
It seems this is a rather popular topic:
odata-expand-dtos-and-entity-framework
how-to-specify-the-shape-of-results-with-webapi2-odata-with-expand
web-api-queryable-how-to-apply-automapper
how-do-i-map-an-odata-query-against-a-dto-to-another-entity
While most of these suggest using ProjectTo, none seem to address serialisation auto expanding properties, or how to handle expansion if ExplictExpansion has been configured.
Classes and Config below:
Entity Framework (V6.1.3) entities:
public class SalesOrderHeader
{
public string SalesOrderNumber { get; set; }
public string Alpha { get; set; }
public string Customer { get; set; }
public string Status { get; set; }
public virtual ICollection<SalesOrderLine> SalesOrderLines { get; set; }
}
public class SalesOrderLine
{
public string SalesOrderNumber { get; set; }
public string OrderLineNumber { get; set; }
public string Product { get; set; }
public string Description { get; set; }
public decimal OrderQuantity { get; set; }
public virtual SalesOrderHeader SalesOrderHeader { get; set; }
public virtual MasterStockRecord MasterStockRecord { get; set; }
}
public class MasterStockRecord
{
public string ProductCode { get; set; }
public string Description { get; set; }
public decimal Quantity { get; set; }
}
OData (V6.13.0) Data Transfer Objects:
public class SalesOrderDto
{
[Key]
public string SalesOrderNumber { get; set; }
public string Customer { get; set; }
public string Status { get; set; }
public virtual ICollection<SalesOrderLineDto> SalesOrderLines { get; set; }
}
public class SalesOrderLineDto
{
[Key]
[ForeignKey("SalesOrderHeader")]
public string SalesOrderNumber { get; set; }
[Key]
public string OrderLineNumber { get; set; }
public string LineType { get; set; }
public string Product { get; set; }
public string Description { get; set; }
public decimal OrderQuantity { get; set; }
public virtual SalesOrderDto SalesOrderHeader { get; set; }
public virtual StockDto MasterStockRecord { get; set; }
}
public class StockDto
{
[Key]
public string StockCode { get; set; }
public string Description { get; set; }
public decimal Quantity { get; set; }
}
OData Config:
var builder = new ODataConventionModelBuilder();
builder.EntitySet<StockDto>("Stock");
builder.EntitySet<SalesOrderDto>("SalesOrders");
builder.EntitySet<SalesOrderLineDto>("SalesOrderLines");
I have created an Automapper explicit navigation expansion utility function that should work with N-deph expands. Posting it here since it might help someone.
public List<string> ProcessExpands(IEnumerable<SelectItem> items, string parentNavPath="")
{
var expandedPropsList = new List<String>();
if (items == null) return expandedPropsList;
foreach (var selectItem in items)
{
if (selectItem is ExpandedNavigationSelectItem)
{
var expandItem = selectItem as ExpandedNavigationSelectItem;
var navProperty = expandItem.PathToNavigationProperty?.FirstSegment?.Identifier;
expandedPropsList.Add($"{parentNavPath}{navProperty}");
//go recursively to subproperties
var subExpandList = ProcessExpands(expandItem?.SelectAndExpand?.SelectedItems, $"{parentNavPath}{navProperty}.");
expandedPropsList = expandedPropsList.Concat(subExpandList).ToList();
}
}
return expandedPropsList;
}
You can call it with :
var navExp = ProcessExpands(options?.SelectExpand?.SelectExpandClause?.SelectedItems)
it will return a list with ["Parent" ,"Parent.Child"]
I never really managed to work this one out. The ToNavigationPropertyArray() extension method helps a little, but does not handle infinite depth navigation.
The real solution is to create Actions or Functions to allow clients to request data requiring a more complicated query.
The other alternative is to make multiple smaller/simple calls then aggregate the data on the client, but this isn't really ideal.
When you want to mark something for explicit expansion in AutoMapper, you need to also opt-back-in when calling ProjectTo<>().
// map
cfg.CreateMap<SalesOrderHeader, SalesOrderDto>()
.ForMember(dest => dest.SalesOrderLines, opt => opt.ExplicitExpansion());
// updated controller
[EnableQuery]
public IQueryable<SalesOrderDto> Get()
{
return _dbContext.SalesOrders
.ProjectTo<SalesOrderDto>(
AutoMapperConfig.Config,
so => so.SalesOrderLines,
// ... additional opt-ins
);
}
While the AutoMapper wiki does state this, the example is perhaps a little misleading by not including the paired ExplicitExpansion() call.
To control which members are expanded during projection, set ExplicitExpansion in the configuration and then pass in the members you want to explicitly expand:

ASP.NET 5 strongly typed configuration JSON format

I am trying to leverage the new ASP.NET 5 configuration builder for the following objects. Does anyone know the JSON syntax for array type fields?
public class ProjectConfiguration
{
public ProjectSubfolder[] ProjectSubfolders { get; set; }
}
public class ProjectSubfolder
{
public string Name { get; set; }
public ProjectPermission[] ProjectPermissions { get; set; }
}
public class ProjectPermission
{
public string Identity { get; set; }
public FileSystemRights FileSystemRights { get; set; }
public InheritanceFlags InheritanceFlags { get; set; }
public PropagationFlags PropagationFlags { get; set; }
public AccessControlType AccessControlType { get; set; }
}
The json I am using which fails to populate the ProjectConfiguration.ProjectSubfolders array looks like:
{
"ProjectConfiguration": {
"ProjectSubfolders": [
{
"Name": "MyName",
"ProjectPermissions": [
{
"Identity": "Domain\\ShortId",
"FileSystemRights": "FileSystemRights.CreateDirectories",
"InheritanceFlags": "InheritanceFlags.None",
"PropagationFlags": "PropagationFlags.NoPropagateInherit",
"AccessControlType": "AccessControlType.Allow"
}
]
}
]
}
}
Epic self fail, when converting from the original XML serializer based implementation, the copy/paste work left the System.Security.AccessControl type names prefixed on the values.
"FileSystemRights": "FileSystemRights.CreateDirectories"
should have been
"FileSystemRights": "CreateDirectories"

Resources