Web API parameter filtering - asp.net-web-api

This must be simple and I'm being incredibly dense but I can't find an example to help me figure it out. I want to filter my list of tblAsset items by their assessmentId which is passed in through a parameter. I'm able to get the parameter value ok, but I'm not sure how to write the query.
My model is built from an existing Database using the Model creation wizard.
Thanks for any help!
public IEnumerable<tblAsset> GettblAssets()
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
var assessmentId = nvc["aid"];
//limit the assets by assessmentId somehow and return
}

You could use the .Where extension method on the IQueryable<tblAsset> instance returned by your database:
public IEnumerable<tblAsset> GettblAssets()
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
var assessmentId = nvc["aid"];
// TODO: you might need to adjust the property names of your model accordingly
// Also if the assessmentId property is an integer on your model type
// you will need to parse the value you read from the request to an integer
// using the int.Parse method
return db.tblAsset.Where(a => a.assessmentId == assessmentId);
}

Related

Grails - Domain object doesn't validate correctly

I'm trying to set the date of birth of a person using jQuery Datepicker. However, all I get is that the Property dateOfBirth must be a valid Date.
So, originally, my controller looks like this:
def update(Person personInstance) {
if (personInstance == null) {
// do Something
return
}
if (personInstance.hasErrors()) {
respond personInstance.errors, view: 'edit'
return
}
// do the rest
}
I figured out, that with jQuery I should use a SimpleDateFormat object in order to generate a proper Date object. Nevertheless, even if I directly assign a new Date object to dateOfBirth and subsequently validating the personInstance domain object - like in the following code segment - I still get the Property dateOfBirth must be a valid Date error.
def update(Person personInstance) {
if (personInstance == null) {
// do Something
return
}
// added code
personInstance.dateOfBirth = new Date()
personInstance.validate()
// added code
if (personInstance.hasErrors()) {
respond personInstance.errors, view: 'edit'
return
}
// do the rest
}
Thank you for any help :)
The reason why you are still seeing errors is because validation is automatically called after binding your command/domain object when the method is called.
Use personInstance.clearErrors() before calling personInstance.validate() manually to clear out any existing binding/validation errors. You can see more about this in the documentation.

MapODataRoute and ODataQueryOptions

Im building a WebAPI OData solution that handles untyped entity objects, as described in this excellent post. Like that post, I define my EdmModel upfront, and use the MapODataRoute method and pass in the model to use:
config.Routes.MapODataRoute("odata", "odata", ModelBuilder.GetEdmModel());
However, this does not seem to work with ODataQueryOptions parameter in my methods:
Get(ODataQueryOptions query)
{
}
It gives the following error: The given model does not contain the type 'System.Web.Http.OData.IEdmEntityObject'. Parameter name: elementClrType
Is there any way to get ODataQueryOptions to work with MapODataRoute?
You should build the ODataQueryOptions manually in your controller action in untyped mode. Sample code follows,
ODataPath path = Request.GetODataPath();
IEdmType edmType = path.EdmType;
IEdmType elementType = edmType.TypeKind == EdmTypeKind.Collection
? (edmType as IEdmCollectionType).ElementType.Definition
: edmType;
// build the typeless query options using the element type.
ODataQueryContext queryContext = new ODataQueryContext(Request.GetEdmModel(), elementType);
ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, Request);
Ive managed to do it as follows:
ODataPath path = Request.GetODataPath();
IEdmType edmType = path.EdmType;
private ODataQueryOptions GetODataQueryOptions(IEdmType edmType)
{
IEdmModel model = Models.ModelBuilder.GetEdmModel();
ODataQueryContext queryContext = new ODataQueryContext(model, edmType);
ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, this.Request);
return queryOptions;
}
This works for most query options, but crashes with $select and $expand: The type 'Collection([Org.Microsoft.Product Nullable=False])' is not an entity type. Only entity types support $select and $expand. Is there a way to avoid this exception gracefully when a client tries to filter with $select and $expand, or should i just write something like
if (Request.RequestUri.Query.Contains("select")) { return errormessage }
Also, and more importantly, how would one apply these query options to an EdmEntityObjectCollection which gets returned in the first method?
queryOptions.ApplyTo(collectionProduct.AsQueryable()); // wont work...
(perhaps it is better practice to dynamically build your collection in regards to the query options anyway)

How do I store a comma-separated list in Orchard CMS?

Using Orchard CMS, I am dealing with a record and a part proxy, but cannot figure out how to save it into the DB. In fact, I confess I don't even know how to get the items I'm trying to save into this paradigm. I was originally using enum's for choices:
MyEmum.cs:
public enum Choices { Choice1, Choice2, Choice3, Choice4 }
MyRecord.cs:
public virtual string MyProperty { get; set; }
MyPart.cs:
public IEnumerable<string> MyProperty
{
get
{
if (String.IsNullOrWhiteSpace(Record.MyProperty)) return new string[] { };
return Record
.MyProperty
.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)
.Select(r => r.Trim())
.Where(r => !String.IsNullOrEmpty(r));
}
set { Record.MyProperty = value == null ? null : String.Join(",", value); }
}
Now, in my service class, I tried something like:
public MyPart Create(MyPartRecord record)
{
MyPart part = Services.ContentManager.Create<MyPart>("My");
...
part.MyProperty = record.MyProperty; //getting error here
...
return part;
}
However, I am getting the following error: Cannot implicitly convert 'string' to System.Collections.Generic.IEnumerable<string>'
Essentially, I am trying to save choices from a checkboxlist (one or more selections) as a comma-separated list in the DB.
And this doesn't even get me over the problem of how do I use the enum. Any thoughts?
For some background:
I understand that the appropriate way to handle this relationship would be to create a separate table and use IList<MyEnum>. However, this is a simple list that I do not intend to manipulate with edits (in fact, no driver is used in this scenario as I handle this on the front-end with a controller and routes). I am just capturing data and redisplaying it in the Admin view for statistical/historical purposes. I may even consider getting rid of the Part (considering the following post: Bertrand's Blog Post.
It should be:
part.MyProperty = new[] {"foo", "bar"};
for example. The part's setter will store the value on the record's property as a comma-separated string, which will get persisted into the DB.
If you want to use enum values, you should use the Parse and ToString APIs that .NET provide on Enum.

Set value in model when dynamically creating object of model

I have a bunch of models that may or may not have a property "CommonProperty". I want to set that property when I am creating a new object of a selected model. What I have so far, which works is:
ModuleItem model = db.ModuleItems.Find(ModuleItemID);
object o = GetModuleType(model.ControllerName);
private object GetModuleType(string ModelName)
{
string projectName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
Type classtype = Type.GetType(string.Format("{0}.Models.{1}", projectName, ModelName));
PropertyInfo[] properties = classtype.GetProperties();
var classObject = classtype.GetConstructor(new Type[] { }).Invoke(null);
return classObject;
}
What I want to achieve is to set CommonProperty:
o.CommonProperty = DistinctValue;
I tried creating a class that all of my models inherit from with a virtual method and each model then has an override method. Because its not static I can't call it directly and if I create a new ModelBase then when calling the method it doesn't get overriden by the type that object "o" is. I looked at creating an interface but 1 I don't even know how these work, and 2 (probably because of 1) I am not even able to create a way of doing this without build errors.
When stepping through the code I can see all the properties of "o" using the quickwatch or intellisense or whatever it's called. Clearly it is being recognised as the correct type. I can't seem to be able to call the method though because it's not a recognised (or set) type during build only during runtime and therefore I can't build the solution.
What I would do is create a base model (eg: BaseModel) for viewmodels that have the property CommonProperty then check whether the model is of type BaseModel then set the property
if (obj is BaseModel)
{
obj.CommonProperty = DistinctValue;
}
As it turns out I was way overthinking this. Typically the answer is ridiculously simple. No base model necessary, no overrides, no virtuals, no instances, dump it in a try catch and just set the value of the context object.
object o = GetModuleType(model.ControllerName);
db.Entry(o).State = EntityState.Added;
try
{
db.Entry(o).CurrentValues["CommonProperty"] = DistinctValue;
}
catch (Exception err) { }
I did have to make sure I set the state BEFORE setting a current value otherwise it wasn't in the context (or something like that).

Reflection + Linq + DbSet

I use EF code-first 4.1. in my application. Now I want to get entities through WCF services using generic types.
I'm trying to reflect generic type and invoke the method ToList of DbSet Object.
Here is my code:
public string GetAllEntries(string objectType)
{
try
{
var mdc =
Globals.DbConnection.Create(#"some_db_connection", true);
// Getting assembly for types
var asob = Assembly.GetAssembly(typeof(CrmObject));
// getting requested object type from assembly
var genericType = asob.GetType(objectType, true, true);
if (genericType.BaseType == typeof(CrmObject))
{
// Getting Set<T> method
var method = mdc.GetType().GetMember("Set").Cast<MethodInfo>().Where(x => x.IsGenericMethodDefinition).FirstOrDefault();
// Making Set<SomeRealCrmObject>() method
var genericMethod = method.MakeGenericMethod(genericType);
// invoking Setmethod into invokeSet
var invokeSet = genericMethod.Invoke(mdc, null);
// invoking ToList method from Set<> invokeSet
var invokeToList = invokeSet.GetType().GetMember("ToList").Cast<MethodInfo>().FirstOrDefault();
//this return not referenced object as result
return invokeToList.ToString();
}
return null;
}
catch (Exception ex)
{
return ex.Message + Environment.NewLine + ex.StackTrace;
}
}
In fact then I write the code like return mdc.Set<SomeRealCrmObject>().ToList() - works fine for me! But then I use the generic types I cannot find the method ToList in object DbSet<SomeRealCrmObject>().
Eranga is correct, but this is an easier usage:
dynamic invokeSet = genericMethod.Invoke(mdc, null);
var list = Enumerable.ToList(invokeSet);
C# 4's dynamic takes care of the cumbersome generic reflection for you.
ToLIst() is not a member of DbSet/ObjectSet but is an extension method.
You can try this instead
var method = typeof(Enumerable).GetMethod("ToList");
var generic = method.MakeGenericMethod(genericType);
generic.Invoke(invokeSet, null);
I had a similar situation where I needed a way to dynamically load values for dropdown lists used for search criteria on a page allowing users to run adhoc queries against a given table. I wanted to do this dynamically so there would be no code change on the front or backend when new fields were added. So using a dynamic type and some basic reflection, it solved my problem.
What I needed to do was invoke a DbSet property on a DbContext based on the generic type for the DbSet. So for instance the type might be called County and the DbSet property is called Counties. The load method below would load objects of type T (the County) and return an array of T objects (list of County objects) by invoking the DbSet property called Counties. EntityList is just a decorator object that takes a list of lookup items and adds additional properties needed for the grid on the front-end.
public T[] Load<T>() where T : class
{
var dbProperty = typeof(Data.BmpDB).GetProperties().FirstOrDefault(
x => x.GetMethod.ReturnType.GenericTypeArguments[0].FullName == typeof(T).FullName);
if (dbProperty == null)
return null;
dynamic data = dbProperty.GetMethod.Invoke(BmpDb, null);
var list = Enumerable.ToList(data) as List<T>;
var entityList = new Data.EntityList<T>(list);
return entityList.Results;
}

Resources