I've one question on how to pass complex object to Web API GET method, where complex object has one more inner object. I've seen examples where there are no inner objects and no one is talking about the complex object which has inner object and what is the best way of achieving that. I have something which is working but I want to know if there are better ways of doing it.
Example without inner object –
public class Name
{
string FName {get; set;}
public string LName { get; set; }
}
[HttpGet]
[Route("Test")]
public void Test([FromUri]Name details)
{
Console.WriteLine(details.ToString());
}
Postman - http://localhost:XXXX/api/NameSearch/Test?FName=Soumen&LName=Banerjee
Here is the example with complext object having inner object.
Example –
public class Address
{
public string Street { get; set; }
public string Zipcode { get; set; }
}
public class Name
{
public string FName {get; set;}
public string LName { get; set; }
public Address Address { get; set; }
}
[HttpGet]
[Route("Test")]
public void Test([FromUri]Name details)
{
Console.WriteLine(details.ToString());
}
Postman - http://localhost:XXXX/api/NameSearch/Test?details.fName=Soumen&details.lName=Banerjee&details.address.street=Mains%20Height&details.address.zipcode=12345
So here you can see that, I've to pass the values using fully qualified name, property and value e.g. details.fname=Soumen or details.address.zipcode=12345. This is different than what I've done in my first example. So, I want to know are there better ways of doing this or this is the only way to pass complex object with inner object(s)? Thank you.
Related
I'm trying to add some info to the data result whether the user has read or write access to the entity.
Lets assume I have this entity:
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Access> AccessRights { get; set; }
}
Where AccessRights holds the user id and if they have read/write access.
Currently I just $expand AccessRights and calculate if the user has read/write access in the frontend. However I'd like this calculated property to be added to the result.
Example json result:
{
id: 1,
name: "foo",
hasReadAccess: true,
hasWriteAccess: true
}
Is it possible to do this? Keep in mind that HasRead/WriteAccess doesn't exist on the model nor should it.
You need to split your model in two: a data access model (what you get from the data access layer) and a data transfer model (what you send as a response).
Assuming your current Foo class as the data access model, you simply need to define another class FooResponse (or whatever name suits you) as follows.
public class FooResponse
{
public int Id { get; set; }
public string Name { get; set; }
public bool HasReadAccess { get; set; }
public bool HasWriteAccess { get; set; }
}
Then define a transformation function that maps from Foo instances to FooResponse instances. AutoMapper is a good tool for the job.
I need to return a collection with nested optional collections from my WebAPI and convert it back to objects in my Web UI, however I'm getting the following error:
Cannot create and populate list type System.Linq.IQueryable`1[MyNamespace.MyClass].
I'm using Json.Net.
Here is a sample of my code:
public class ClassA
{
public Int64 Id { get; set; }
public String Description { get; set; }
public IEnumerable<ClassB> { get; set; }
}
public class ClassB
{
public Int64 Id { get; set; }
public String Description { get; set; }
}
I've saw some questions here in stackoverflow, but I don't have access to serialization options (it is handled internally by our library).
UPDATE
I've forgot to mention that ClassA is returned as an IQueryable in my Web API.
Changing the return type of my Web API method to IEnumerable instead of IQueryable solved the problem.
I think I am missing a simple solution here. When I run a select (using Linq-style on IQueryable) that returns IQueryable, I may want MyClass to return differently-formatted key/values than I will use in my insert.
Consider as example the below UploadFile class and note properties id and Filetimestamp. When I SET Filetimestamp I want it stored as DateTime, but when I RETRIEVE IQueryable I would like to:
See Filetimestamp returned as String
OR
See a separate property returned as String reflecting Filetimestamp.toString(). This property doesn't have a corresponding key in the database; it's just a decoration of a real key/value from BSON.
Thinking #1 was unlikely, I pursued #2 by adding a get-only field Filetimestamp_str that returns Filetimestamp.toString(). When I select, behavior is as expected. When I insert, I see failures.
I could create a decorator class that I use for gets and all would work - but am I missing something more fundamental and simple here?
public class UploadFile : IUploadFile
{
public Object _id { get; set; }
public String Filepath { get; set; }
public String Filename { get; set; }
public String Filetype { get; set; }
public String Fileauthor { get; set; }
public DateTime Filetimestamp { get; set; }
public Object FileID { get; set; }
// these keys are not in DB
public String Filetimestamp_str { get { return Filetimestamp.ToString(); } }
public String _id_str { get { return _id.ToString(); } }
}
You could create a BsonClassMap, specifying which properties should (not) be serialized. See the Serialization Tutorial. However, according to that tutorial, a read-only property should not be automapped, so I should not expect errors on the insert.
This is a follow up to this:
What does MVC3 do with C# Optional Parameters?
I have an action with the following signature:
public ViewResult Show(int Id, PublishingErrorSummary pubErrors=null, String title=null)
On requesting server/show/1 pubErrors is not null, but title is null. How is it possible? These are just two objects but string somehow manages to become null. Where can I fix this?
Edit: class definition added
public class PublishingErrorSummary
{
public List<string> StepOneErrors { get; set; }
public List<string> StepTwoErrors { get; set; }
public List<string> StepThreeErrors { get; set; }
public List<string> StepFourErrors { get; set; }
}
PublishingErrorSummary is a complex object. The default model binder always initializes complex objects. It doesn't really make sense to set its default value to null. Same stands for the title parameter. Strings are reference types and their default value will be null anyway if no request parameter title is sent.
I have an abstract class
public abstract class Member
{
public string ID { get; set; }
public string Username { get; set; }
public int MemberType { get; set; }
public abstract string MemberName { get; set; }
public int Status { get; set; }
}
public class Person : Member
{
public string LastName { get; set; }
public string FirstName{ get; set; }
}
public class Business : Member
{
public string BusinessName { get; set; }
public string TaxNo { get; set; }
}
The class was mapped using fluent API,
Now, is there a way to update the "Status" property from the view(having Member model) without using or going to a subclass (Person/Business)?
I just tried it, but it says "Cannot create an abstract class.", when submitting the page.
Or there is a correct way to do this?
Thanks
Not in EF. You have to instantiate an object to work with EF, and you can't instantiate an abstract class.
You could make the class not be abstract. Or you could use a stored proc to update the field, or some direct sql.
It sounds like your problem is that your action method has an abstract type as a parameter, which the default model binder can't do anything with. If you are dead set on using the same view for two different classes, you may need to implement your own model binder to inspect in the incoming request and decide which type, Person or Business, to instantiate.
Check out this link for more information on creating a custom model binder:
http://odetocode.com/blogs/scott/archive/2009/05/05/iterating-on-an-asp-net-mvc-model-binder.aspx
This seems like a similar problem to the one I've answered previously here:
ASP.NET MVC 3: DefaultModelBinder with inheritance/polymorphism