$select on navigation property / WebApi 2.0 / OData 4 - asp.net-web-api

Given the following simple OData 4 controller (please see below), how do I $select just the cities?
http://localhost//api/Customers?$select=Location
Gives me:
{
"#odata.context":"http://localhost/api/$metadata#Customers(Location)","value":[
{
"Location":{
"Country":"Ireland","City":"Sligo"
}
},{
"Location":{
"Country":"Finland","City":"Helsinki"
}
}
]
}
But I don't know how to drill down one deeper so that I just get the cities. Is this even possible?
public class CustomersController : ODataController
{
private List<Customer> customers = new List<Customer>()
{
new Customer
{
CustomerId = 1,
Location = new Address
{
City = "Sligo",
Country = "Ireland"
}
},
new Customer
{
CustomerId = 2,
Location = new Address
{
City = "Helsinki",
Country = "Finland"
}
}
};
[EnableQuery]
public List<Customer> Get()
{
return customers;
}
}

The grammar for $select does not allow a path expression like Location/City. Your best bet is to define an OData function bound to the Customers entity set. E.g.,
[HttpGet]
public IEnumerable<string> GetCities()
{
return customers.Select(c => c.Location.City);
}
And invoke it as follows:
GET http://localhost/api/Customers/ServiceNamespace.GetCities

Related

MongoDB search nested objects in an array

I am using MongoDB to store all the events in my Eventbrite clone. So I have a collection called events then the objects in this collection consists of their name and and array of users that have rsvp to the event. I can query for any events that the current user has created but unable to figure out how to query both events the user has created and rsvp to.
Here is the compiled query that I am using to try to get all the users events.
events.find({"$and":[{"user_id":"5d335704802df000076bad97"},{"user_id":{"$ne":null}}],"$or":[{"checkins.user_id":"5d335704802df000076bad97"}]},{"typeMap":{"root":"array","document":"array"}})
I am using the Laravel MongoDB plugin to query my data in php it looks like this
$user->events()->orWhere(function ($query) use ($user){
return $query->where('checkins.user_id',new ObjectID($user->id));
})->get()
The event object looks something like this:
{
"name": "test",
"user_id": "1"
"rsvp": [
{"user_id": "12"}
]
}
An user can rsvp to other event that are not their own.
you need an $or filter and $elemMatch to get events that belong to a given user or events they've rsvp'd to.
db.events.find({
"$or": [
{
"user_id": "5d33e732e1ea9d0d6834ef3d"
},
{
"rsvp": {
"$elemMatch": {
"user_id": "5d33e732e1ea9d0d6834ef3d"
}
}
}
]
})
unfortunately i can't help you with laravel version of the query. in case it helps, below is the c# code that generated the above mongo query.
using MongoDB.Entities;
using System.Linq;
namespace StackOverflow
{
public class Program
{
public class user : Entity
{
public string name { get; set; }
}
public class Event : Entity
{
public string name { get; set; }
public string user_id { get; set; }
public rsvp[] rsvp { get; set; }
}
public class rsvp
{
public string user_id { get; set; }
}
private static void Main(string[] args)
{
new DB("test");
var mike = new user { name = "mike" };
var dave = new user { name = "dave" };
mike.Save();
dave.Save();
(new[] {
new Event
{
name = "mike's event",
user_id = mike.ID,
rsvp = new[]
{
new rsvp { user_id = dave.ID }
}
},
new Event
{
name = "dave's event",
user_id = dave.ID,
rsvp = new[]
{
new rsvp { user_id = mike.ID }
}
}
}).Save();
var result = DB.Find<Event>()
.Many(e =>
e.user_id == mike.ID ||
e.rsvp.Any(r => r.user_id == mike.ID));
}
}
}

How to get attributes from OData response via AJAX?

I'm working on the MVC application which using OData & Web API via ajax. I'm trying to do paging from server side by using OData filter attributes. Here is my code of Controller.
[RoutePrefix("OData/Products")]
public class ProductsController : ODataController
{
private List<Product> products = new List<Product>
{
new Product() { Id = 1, Name = "Thermo King MP-3000", Price = 300, Category = "Thermo King" },
new Product() { Id = 2, Name = "Thermo King MP-4000", Price = 500, Category = "Thermo King" },
new Product() { Id = 3, Name = "Daikin Decos III c", Price = 200, Category = "Daikin" },
new Product() { Id = 4, Name = "Daikin Decos III d", Price = 400, Category = "Daikin" },
new Product() { Id = 5, Name = "Starcool RCC5", Price = 600, Category = "Starcool" },
new Product() { Id = 6, Name = "Starcool SCC5", Price = 700, Category = "Starcool" }
};
[EnableQuery(PageSize=2)]
public IQueryable<Product> Get()
{
return products.AsQueryable<Product>();
}
//[EnableQuery]
//public SingleResult<Product> Get([FromODataUri] int id)
//{
// var result = products.Where(x => x.Id.Equals(id)).AsQueryable();
// return SingleResult.Create<Product>(result);
//}
[EnableQuery]
public Product Get([FromODataUri] int id)
{
return products.First(x => x.Id.Equals(id));
}
}
And here is my code of javascript:
<script type="text/javascript">
$(document).ready(function () {
var apiUrl = "http://localhost:56963/OData/Products";
$.getJSON(apiUrl,
function (data) {
$("#div_content").html(window.JSON.stringify(data));
}
);
//$.get(apiUrl,
//function (data) {
// alert(data[0]);
// $("#div_content").html(data);
//});
});
</script>
The response from OData is JSON result like:
{"#odata.context":"http://localhost:56963/OData/$metadata#Products","value":[{"Id":1,"Name":"Thermo King MP-3000","Price":300,"Category":"Thermo King"},{"Id":2,"Name":"Thermo King MP-4000","Price":500,"Category":"Thermo King"}],"#odata.nextLink":"http://localhost:56963/OData/Products?$skip=2"}
I was trying to get "#odata.nextLink" but failed, there is no way to get "odata.nextLink" by "data.#odata.nextLink" from javascript.
Any one can help me to get through this?
After parse the string to json, data['#odata.nextLink'] can work:
var data = '{"#odata.context":"http://localhost:56963/OData/$metadata#Products","value":[{"Id":1,"Name":"Thermo King MP-3000","Price":300,"Category":"Thermo King"},{"Id":2,"Name":"Thermo King MP-4000","Price":500,"Category":"Thermo King"}],"#odata.nextLink":"http://localhost:56963/OData/Products?$skip=2"}';
data = JSON.parse(data);
alert(data['#odata.nextLink']);

MVC3 Areas routing conflict

Question: i want my route to be like that
/admin/main/category/1 -> 1 == ?page=1
i don't want page=1 to be seen
My Controller
public class MainController : BaseController
{
private const int PageSize = 5; //pager view size
[Inject]
public ICategoryRepository CategoryRepository { get; set; }
public ActionResult Index()
{
return View();
}
public ActionResult Category(int page)
{
//int pageIndex = page.HasValue ? page.Value : 1;
int pageIndex = page != 0 ? page : 1;
return View("Category", CategoryViewModelFactory(pageIndex));
}
/*
*Helper: private instance/static methods
======================================================================*/
private CategoryViewModel CategoryViewModelFactory(int pageIndex) //generate viewmodel category result on pager request
{
return new CategoryViewModel
{
Categories = CategoryRepository.GetActiveCategoriesListDescending().ToPagedList(pageIndex, PageSize)
};
}
}
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRouteLowercase(
"AdminCategoryListView",
"admin/{controller}/{action}/{page}",
new { controller = "Category", action = "Category", page = "1" },
new { id = #"\d+" },
new[] { "WebUI.Areas.Admin.Controllers" }
);
}
}
My Exception:
The parameters dictionary contains a null entry for parameter 'page'
of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult Category(Int32)' in
'WebUI.Areas.Admin.Controllers.MainController'. An optional parameter
must be a reference type, a nullable type, or be declared as an
optional parameter. Parameter name: parameters
Thank you all in advance.
Make sure that in your Admin area route registration you have defined the {page} route token instead of {id} which is generated by default:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{page}",
new { action = "Index", page = UrlParameter.Optional }
);
}
Now when you are generating links make sure you specify this parameter:
#Html.ActionLink(
"go to page 5", // linkText
"category", // actionName
"main", // controllerName
new { area = "admin", page = "5" }, // routeValues
null // htmlAttributes
)
will emit:
go to page 5
and when this url is requested the Category action will be invoked and passed page=5 parameter.

Can I display contents of Application or Cache objects using Glimpse in an MVC project?

The ASP.NET WebForms trace output has a section for Application State. Is it possible to see the same using Glimpse?
In my home controller's Index() method, I tried adding some test values, but I don't see the output in any of the Glimpse tabs.
ControllerContext.HttpContext.Application.Add("TEST1", "VALUE1");
ControllerContext.HttpContext.Cache.Insert("TEST2", "VALUE2");
I didn't see anything in the documentation either.
I don't think that there is an out-of-the-box support for this, but it would be trivial to write a plugin that will show this information.
For example to show everything that's stored in the ApplicationState you could write the following plugin:
[Glimpse.Core.Extensibility.GlimpsePluginAttribute]
public class ApplicationStateGlimpsePlugin : IGlimpsePlugin
{
public object GetData(HttpContextBase context)
{
var data = new List<object[]> { new[] { "Key", "Value" } };
foreach (string key in context.Application.Keys)
{
data.Add(new object[] { key, context.Application[key] });
}
return data;
}
public void SetupInit()
{
}
public string Name
{
get { return "ApplicationState"; }
}
}
and then you get the desired result:
and to list everything that's stored into the cache:
[Glimpse.Core.Extensibility.GlimpsePluginAttribute]
public class ApplicationCacheGlimpsePlugin : IGlimpsePlugin
{
public object GetData(HttpContextBase context)
{
var data = new List<object[]> { new[] { "Key", "Value" } };
foreach (DictionaryEntry item in context.Cache)
{
data.Add(new object[] { item.Key, item.Value });
}
return data;
}
public void SetupInit()
{
}
public string Name
{
get { return "ApplicationCache"; }
}
}

Storing ActionLink in model or RouteValueDictionary in model

I wish to store an action link in the model.
Something like
public MvcHtmlString ActionLink_New
{
get { return Html.ActionLink("new", "Edit", "News", new { Area = "Admin" }, null); }
}
It appears the model needs a webviewpage context.
Failing that, I thought I would store just the route values.
public RouteValueDictionary[] RouteValue_New
{
get { return new RouteValueDictionary[] { Area = "Admin" }; }
}
//View
#Html.ActionLink("new", "Edit", "News", Model.RouteValue_New, null)
The Area in the property is red. Is either or both scenario achievable. What do i need to add to get this to work, thanks.
try this
public object RouteValue_New
{
get {
return new { Area = "Admin" };
}
}

Resources