OData v4 $orderby on a child derived property - odata

I have the following scenario:
public class Stay
{
[Contained]
public Guest PrimaryGuest {get;set;}
}
public abstract class Guest
{
public int ID {get; set;}
}
public class EntityGuest : Guest
{
public string EntityName {get;set;}
}
public class PersonGuest : Guest
{
public string SurName {get;set;}
public string GivenName {get;set;}
}
When querying for the stays, I wish to order by a PersonGuest/SurName.
I know how to order by a child property: [URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/ID - but how would I order by on a child property that is derived? Is it even possible? I could not determine it by the OData documentation - it wasn't at least called out for contained entities.

This answer helped me a lot in a similar scenario: oData $expand on Derived Types
Basically you can 'Cast' any complex or entity typed property in your query by adding a forward slash and the qualified name of the model type, using the namespace you have defined for your model, not the .Net full type name.
[URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/ModelNamespace.PersonGuest/Surname
If you are unsure of the model namespace, look at the model builder code, or use something similar to this:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "MyAppModel";
Then your URL should look like this:
[URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/MyAppModel.PersonGuest/Surname

Related

ASP.Net MVC Controller FromUri to Model - Can we define the order?

In my applicantion, I browse to the URL by supplying the parameters through query string. Based on the URI, the respective controller's action is triggered, and the parameters supplied are auto-mapped to my model.
URL: http://{host}:{port}/{website}/{controller}/{action}?{querystring}
URI:
/{controller}/{Action}?{QueryString}
My URI: Employee/Add?EmployeeCode=Code3&EmployeeId=103
EmployeeModel
public class EmployeeModel
{
public Employee()
{
}
public string EmployeeId { get; set; }
public string EmployeeCode { get; set; }
//Some more properties here
}
EmployeeController
[HttpGet]
[Route("Add")]
public IActionResult Add([FromUri] EmployeeModel model)
{
//Some code here
}
While this all works fabulous, when I browse through, below is the order in which break-points hit,
Add method of EmployeeController
Default constructor of EmployeeModel
set method of EmployeeId property of EmployeeModel
set method of EmployeeCode property of EmployeeModel
I suspect the order in which the properties get initialized is based on the order they are declared in the class.
But, to create an instance and initialize the properties the framework must be using reflection. And as per the MSDN documentation for Type.GetProperties the order is not guarateed.
The GetProperties method does not return properties in a particular
order, such as alphabetical or declaration order. Your code must not
depend on the order in which properties are returned, because that
order varies.
I basically want the initialization to take place in a specific order, is this possible?
You can't get the model binding mechanism to do things in a specific order, but you can make sure that the order is applied where it has to be.
Presumably, EmployeeModel is a domain model object on which the order actually matters, and you're now model binding directly to this type. Instead, introduce an edit model1 which you model bind to, and then map that to your model type:
public class EmployeeEditModel
{
public string EmployeeId { get; set; }
public string EmployeeCode { get; set; }
}
// and change your action signature to this:
[HttpGet]
[Route("Add")]
public IActionResult Add([FromUri] EmployeeEditModel model)
1 For an explanation of what an edit model is, see the final remarks on this old answer of mine.
To perform the mapping you have numerous alternatives, some better than others. Pick one that suits you - however, since the reason the order matters is probably something inherent in the domain model object, I'd advice you to put the logic inside it (e.g. in a constructor), to make it easier to remember to change it if the requirements change.
Map via a constructor on the model object
public class EmployeeModel
{
public EmployeeModel(string employeeId, string employeeCode /* , ... */)
{
// do stuff in whatever order you need
EmployeeId = employeeId;
EmployeeCode = employeeCode;
}
// Now your properties can be get-only
public string EmployeeId { get; }
public string EmployeeCode { get; }
}
Map via an extension method that does everything in the right order
public static class EmployeeEditModelExtensions
{
public EmployeeModel AsDomainModel(this EmployeeEditModel editModel)
{
// do stuff in whatever order you need
var model = new EmployeeModel();
model.EmployeeId = editModel.EmployeeId;
model.EmployeeCode = editModel.EmployeeCode;
// ...
}
// Now your properties can be get-only
public string EmployeeId { get; }
public string EmployeeCode { get; }
}
Use an external framework such as AutoMapper, with custom configuration to make sure that the ordering is correct
Do something else. The only purpose is to get you from an EmployeeEditModel instance to an EmployeeModel instance, assigning to the properties of the EmployeeModel in the correct order. Since you write this code yourself, you can do what you want.

Where to put extra view data that doesnt relate to view data

So, lets look at an example. I have a Customer view model that looks like this:
public class CustomerViewModel {
public string Name {get; set;}
public int CustomerTypeId {get; set;}
}
On the UI there needs to be a drop down of customer types. In order to populate this, something needs to go to the business layer or data layer and grab this list of customer types.
It seems to me that this logic doesn't really belong in CustomerViewModel since it isn't really customer data; only CustomerTypeId is. So my question is, where in general (not necessarily in .net MVC, but general practice for the MVC view model concept) do people put this data access?
Is it acceptable to have a function in the view model itself called GetCustomerTypes()?
public class CustomerViewModel {
public string Name {get; set;}
public int CustomerTypeId {get; set;}
public List<CustomerType> GetCustomerTypes() { ... }
}
Should I make a class/method in the business layer or a helper and import the code manually in the view to access this function? It seems to me like this would be code that clutters up the view and doesn't belong there.
#{
using My.App.CustomerTypeHelper;
var helper = new CustomerTypeHelper();
var customerTypes = helper.GetCustomerTypes();
}
...
#Html.DropDownFor(x => x.CustomerTypeId, customerTypes)
The global Html helper eases this problem a bit in .Net, but I am looking for a more global solution conceptually that I can apply to PHP code, etc also. PHP doesn't have the ability to cleanly have a static class that can be separated into small organized units with extension methods. So any global helper is likely to get large and ugly.
You should include List<CustomerType> in the model but do NOT implement function inside the model. Set the data from controller instead.
Something like this:
public class CustomerViewModel {
public string Name {get; set;}
public int CustomerTypeId {get; set;}
public List<CustomerType> CustomerTypes { get; set; }
}
Assign data to ViewModel from Controller:
var model = new CustomerViewModel();
model.CustomerTypes = Customer.GetCustomerTypes();
You could have a class that is 'shared' between models that has all the definitions of such data. I would go with something such as:
public static partial class StaticData
{
public static List<CustomerType> CustomerTypes = new Lisr<CustomerType>
{
new CustomerType { Name = "Whatever", Discount = 10, ....... },
new CustomerType { Name = "Another", Discount = 0, ........}
// etc
}
}
Notice this is a partial class so you can split this across files/folders in you project and have:
CustomerTypes.cs
SupplierTypes.cs
ProductTypes.cs
And anything else as separate files all building into a shared StaticData class that end up containing all your definitions for drop-downs and any other non-database information.
So then, in your view, you can populate your select options using StaticData.CustomerTypes.
The CustomerModel (not ViewModel, because there is no ViewModel in MVC) is not the model of a Customer. It is the model used in the view Customer. If that view needs this information, it should be in that model.
It is not clear to me what that view does in your application, but it looks like some customer creation form. Just calling it CustomerModel doesn't explain the intent of the class very well. You might want to call your model CreateModel, used in Create.cshtml that is returned from the Create() method in the CustomerController. Then it makes sense to add the CustomerTypes to this model: you need to have CustomerTypes if you want to create a customer.

how to hide or show links based not only on roles but other business logic

My MVC application has a handful of roles. ex Admin,General. I use a CustomRoleProvider but then in the view I do following
#if (Roles.IsUserInRole("admin"))
{
<div class="editor-label">#Html.RadioButton("selection", "View Project Details", false)View Project Details</div>
}
Recently I was told to additionally restrict access based on business logic ex. if createdby user on a Project was 'xyz',allow 'xyz' access to the link.
I know one way would be to check the controller and return different views based on the Roles and BusinessLogic. Thats going to be unmanageable!!
is there any other way to achieve this?
You can just store permissions in your model or in ViewBag and use if statements as above. You can also create method like IsInBuissnesRole and implement logic inside it.
I have answered similar question here.
Basically you should use viewmodel with properties denoting if certain features of the view should be enabled/visible to user. Then it is controller (maybe based onr some business logic service) should set these values.
Example:
// Model
public class Procuct
{
public int Id {get; set;}
public string Name {get;set;}
}
// Viewmodel
public class ProcuctViewModel
{
public int Id {get; set;}
public string Name {get;set;}
public bool CanEdit {get;set;}
public bool CanDelete {get; set;}
}
// somewhere in controller
var product = new ProductViewModel(_repo.GetProductById(1));
if (Roles.IsUserInRole("admin"))
{
product.CanEdit = true;
}
// ...
return View(product);
Then your view gets simpler and all the security stuff is moved to controller and is unittestable

Web API Error: The 'ObjectContent`1' type failed to serialize the response body for content type

I am getting this error when attempting to use a Web API controller.
Web API Error: The 'ObjectContent`1' type failed to serialize the response body for content type
the code in my controller is as follows
public IEnumerable<Student> GetAllStudents()
{
var allstudents = unitOfWork.StudentRepository.Get(includeProperties: "Groups");
return allstudents;
}
public Student GetStudentByID(Guid id)
{
return unitOfWork.StudentRepository.GetByID(id);
}
and my 'Student' class is as follows
public partial class Student
{
public Student()
{
this.Groups = new HashSet<Group>();
}
public System.Guid StudentID { get; set; }
public string Surname { get; set; }
public string FirstName { get; set; }
public byte[] Timestamp { get; set; }
public virtual Course Course { get; set; }
public virtual ICollection<Group> Groups { get; set; }
}
Both methods result in the same error.
My inner exception is as follows
Type
'System.Data.Entity.DynamicProxies.Student_4C97D068E1AD0BA62C3C6E441601FFB7418AD2D635F7F1C14B64F4B2BE32DF9A'
with data contract name
'Student_4C97D068E1AD0BA62C3C6E441601FFB7418AD2D635F7F1C14B64F4B2BE32DF9A:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies'
is not expected. Consider using a DataContractResolver or add any
types not known statically to the list of known types - for example,
by using the KnownTypeAttribute attribute or by adding them to the
list of known types passed to DataContractSerializer.
I have a feeling I need to use the KnownType attribute but I'm not exactly sure how to implement it.
Any help would be appreciated
If you don't need the lazy-loaded navigation properties provided by the proxy class (System.Data.Entity.DynamicProxies.Student_4C97D068E1A...), you can disable their generation by setting:
unitOfWork.Configuration.ProxyCreationEnabled = false;
What to do if you need the proxy class is another question.
Follow these links for a good overview of lazy loading and proxies:
Loading Related Entities
Working with Proxies
Should I enable or disable dynamic proxies
I usually disable lazy loading and proxies by default, and enable one or both in specific code blocks that need them.
What is the inner exception message? The inner exception message will be the actual exception that is thrown by the serializer and it should tell us which type is causing the exception.
Let me guess -- Is it any the type Course and the type Group? If so, try putting KnownType attribute on the actual implementation type of your class Student
[KnownType(typeof(GroupA))]
[KnownType(typeof(CourseA))]
public partial class Student
{...}
public class GroupA : Group {...}
public class CourseA : Course {...}
public interface Group {...}
public interface Course {...}

Composing polymorphic objects in ASP.NET MVC3 project

The essence of my question is how to compose these objects (see below) in a sensible way with MVC3 and Ninject (though I am not sure DI should be playing a role in the solution). I can't disclose the real details of my project but here is an approximation which illustrates the issue/question. Answers in either VB or C# are appreciated!
I have several different products with widely varying properties yet all of them need to be represented in a catalog. Each product class has a corresponding table in my database. A catalog entry has a handful of properties specific to being a catalog entry and consequently have their own table. I have defined an interface for the catalog entries with the intent that calling the DescriptionText property will give me very different results based on the underlying concrete type.
Public Class Clothing
Property Identity as Int64
Property AvailableSizes As List(Of String)
Property AvailableColor As List(Of String)
End Class
Public Class Fasteners
Property Identity as Int64
Property AvailableSizes As List(Of String)
Property AvailableFinishes As List(Of String)
Property IsMetric As Boolean
End Class
Public Interface ICatalogEntry
Property ProductId as Int64
Property PublishedOn As DateTime
Property DescriptionText As String
End Interface
Given that the DescriptionText is a presentation layer concern I don't want to implement the ICatalogEntry interface in my product classes. Instead I want to delegate that to some kind of formatter.
Public Interface ICatalogEntryFormatter
Property DescriptionText As String
End Interface
Public Class ClothingCatalogEntryFormatter
Implements ICatalogEntryFormatter
Property DescriptionText As String
End Class
Public Class FastenerCatalogEntryFormatter
Implements ICatalogEntryFormatter
Property DescriptionText As String
End Class
In a controller somewhere there will be code like this:
Dim entries As List(Of ICatalogEntry)
= catalogService.CurrentCatalog(DateTime.Now)
In a view somewhere there will be code like this:
<ul>
#For Each entry As ICatalogEntry In Model.Catalog
#<li>#entry.DescriptionText</li>
Next
</ul>
So the question is what do the constructors look like? How to set it up so the appropriate objects are instantiated in the right places. Seems like generics or maybe DI can help with this but I seem to be having a mental block. The only idea I've come up with is to add a ProductType property to ICatalogEntry and then implement a factory like this:
Public Class CatalogEntryFactory
Public Function Create(catEntry as ICatalogEntry) As ICatalogEntry
Select Case catEntry.ProductType
Case "Clothing"
Dim clothingProduct = clothingService.Get(catEntry.ProductId)
Dim clothingEntry = New ClothingCatalogEntry(clothingProduct)
Return result
Case "Fastener"
Dim fastenerProduct = fastenerService.Get(catEntry.ProductId)
Dim fastenerEntry = New FastenerCatalogEntry(fastenerProduct)
fastenerEntry.Formatter = New FastenerCatalogEntryFormatter
Return fastenerEntry
...
End Function
End Class
Public ClothingCatalogEntry
Public Sub New (product As ClothingProduct)
Me.Formatter = New ClothingCatalogEntryFormatter(product)
End Sub
Property DescriptionText As String
Get
Return Me.Formatter.DescriptionText
End Get
End Property
End Class
...FastenerCatalogEntry is omitted but you get the idea...
Public Class CatalogService
Public Function CurrentCatalog(currentDate as DateTime)
Dim theCatalog As List(Of ICatalogEntry)
= Me.repository.GetCatalog(currentDate)
Dim theResult As New List(Of ICatalogEntry)
For Each entry As ICataLogEntry In theCatalog
theResult.Add(factory.Create(entry))
Next
Return theResult
End Function
End Class
IMHO, I am not really getting any smells off this code other than having to change the factory for every new product class that comes along. Yet, my gut says that this is the old way of doing things and nowadays DI and/or generics can do this better. Suggestions on how to handle this are much appreciated (as are suggestions on a better title...)
I like to just use the default constructor on models for the view and populate them via Automapper.
I would have a view model like this:
public interface IHasDescription
{
public string DescriptionText { get; set; }
}
public class ViewModelType : IHasDescription
{
[DisplayName("This will be rendered in the view")]
public string SomeText { get; set; }
public string DescriptionText { get; set; }
}
And I have a model from the DAL like this:
public class DALModelType
{
public string SomeText { get; set; }
}
So you have something like this in your controller:
var dalModel = someRepository.GetAll();
var viewModel = Mapper.Map<DALModelType, ViewModelType>(dalModel);
And you have the Automapper setup code in some file. This way you only have the conversion code in one place instead of in multiple methods/controllers. You have a custom resolver which uses dependency injection (instead of () => new CustomResolver()) and this will house your logic for getting the display text.
Mapper.CreateMap<IHasDescription, ViewModelType>()
.ForMember(dest => dest.DescriptionText,
opt => opt.ResolveUsing<CustomResolver>().ConstructedBy(() => new CustomResolver()));
Not sure if this works with your workflow but it should be able to get you what you want.
So making a few small changes I got this to work using the Ninject Factory extension.
Biggest change is that my entities have enough info to display either type (clothes or fasteners in my contrived example) if the item is actually clothes then the fastener specific properties will be null and vice versa.
Public Interface IDescribable
ReadOnly Property DescriptionText As String
End Interface
Public Enum ProductType
CLOTHING
FASTENER
End Enum
Public Interface ICatalogEntry
Inherits IDescribable
ReadOnly Property ProductId As Int64
ReadOnly Property PublishedOn As DateTime
ReadOnly Property ProductType As ProductType
End Interface
Public Class CatalogEntryEntity
Public Property ProductId As Long
Public Property ProductType As ProductType
Public Property PublishedOn As Date
Public Property DescriptionText As String
Public Property Color As String
Public Property Finish As String
Public Property IsMetric As Boolean
End Class
Then with this in place I can define my catalog service as follows:
Public Class CatalogService
Private ReadOnly _factory As ICatalogEntryFactory
Private ReadOnly _repository As CatalogRepository
Public Sub New(entryFactory As ICatalogEntryFactory, repository As CatalogRepository)
Me._factory = entryFactory
Me._repository = repository
End Sub
Public Function CurrentCatalog(currentDate As DateTime) As List(Of ICatalogEntry)
Dim items = Me._repository.GetCatalog()
Return (From item In items Select _factory.Create(item.ProductType.ToString(), item)).ToList()
End Function
End Class
Public Interface ICatalogEntryFactory
Function Create(bindingName As String, entity As CatalogEntryEntity) As ICatalogEntry
End Interface
Ninject will provide the factory (which is awesome!) assuming I setup the bindings like this:
theKernel.Bind(Of ICatalogEntry)().To(Of ClothingCatalogEntry)().Named("CLOTHING")
theKernel.Bind(Of ICatalogEntry)().To(Of FastenerCatalogEntry)().Named("FASTENER")
theKernel.Bind(Of ICatalogEntryFactory)().ToFactory(Function() New UseFirstParameterAsNameInstanceProvider())
I've omitted the FastenerCatalogEntry for brevity; the ClothingCatalogEntry is like this:
Public Class ClothingCatalogEntry
Public Sub New(ByVal entity As CatalogEntryEntity)
...
It was this post that helped me the most to figure this out. I used UseFirstParameterAsNameInstanceProvider exactly as shown there.

Resources