Azure Table Controllers - Get records by to parameters - c#

I am working on an Azure Mobile Apps project. Where I have to define a Table Controller with that can accept two parameters and give a list of values. I have a DataObject for ProductItem, which is
public class ProductItem : EntityData
{
public string Name { get; set; }
public string Details { get; set; }
public double Price { get; set; }
public string Image { get; set; }
public Merchant Merchant { get; set; }
}
I need to get a specific Product item, filter by its Price and Merchant. Already in the ProductItemContoller, I have scaffolded
// GET tables/ProductItem
public IQueryable<ProductItem> GetAllProductItems()
{
return Query();
}
// GET tables/ProductItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public SingleResult<ProductItem> GetProductItem(string id)
{
return Lookup(id);
}
by looking at existing examples. But in examples, we have not called any of the given methods from Client. Rather, IEnumerable<ProductItem> items = await productTable.ToEnumerableAsync(); was called.
My question is why can't we call GetAllProductItems() which was already defined in the controller to the client. If we can call, how to do it.
And also, I need to have a controller method, I need to have a GetAllProductByMerchat(string merchantId). How can I make this possible.

The Table controllers are called automatically by the client SDKs on your behalf, allowing you to work with LINQ queries on the client. You can use something like:
var items = productTable.Where(p => p.Price < 100).ToListAsync();
This gets translated into an OData query across the wire, then translated back into a LINQ query on the server, where it then gets translated into SQL and executed on the SQL Azure instance.
For more information, see chapter 3 of http://aka.ms/zumobook

Did you mean this?
// Server method:
[HttpGet]
[Route("GetAllProductItems")]
public IQueryable<ProductItem> GetAllProductItems()
{
return Query();
}
// Client call
var result = await MobileService.InvokeApiAsync<IQueryable<ProductItem>>("ProductItem/GetAllProductItems", HttpMethod.Get, null);
Remember to add these attribute before the ProductItemController:
[MobileAppController]
[RoutePrefix("api/ProductItem")]
You can do the same thing to your GetAllProductByMerchat(string merchantId) method.

Related

How to pass multiple parameters to Get Method and Route them in .NET Core Web API?

I'm making a (restful) Web API in .NET Core and stumbled among some problems.
I cannot seem to find how to pass multiple subscription ID's... I need to be able to show multiple periods(invoices) of multiple subscriptions.
My route at the moment is
[Route("tenants/{tenantId:long}/subscriptions/{subscriptionId:long}/invoices/{invoiceId:long}/categories")]
From this way it seems impossible for me to pass more subscription IDs.
Some terms I found but not fully understand are:
Model Binding
[FromQuery]
My classes:
public class Subscription
{
public string Name { get; set; }
public long TenantId { get; set; }
public string Guid { get; set; }
}
public class Invoice
{
public long SubscriptionId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public long PortalId { get; set; }
}
My controllers with routes [Route("tenants/{tenantId:long}/subscriptions")] and [Route("tenants/{tenantId:long}/subscriptions/{subscriptionId:long}/invoices")]
[HttpGet]
public IEnumerable<SubscriptionViewModel> Find(long tenantId)
{
var subscriptionList = _subscriptionManager.Find(tenantId);
...
return subscriptionViewModels;
}
[HttpGet]
public IEnumerable<InvoiceViewModel> Find(long subscriptionId)
{
var invoiceList = _invoiceManager.Find(subscriptionId);
...
return invoiceViewModels;
}
Please note that i'm using a Mapper for my data (which is why i'm using ViewModels).
The currently written code is for a specific subscription.
I am looking for a Route like /api/invoices?subscriptionId=x,y,z
I understand(?) I need the [FromQuery] for that, but I cannot seem to find out how, especially if my parameter (subscriptionId) stays the same.
for the requirement which you have mentioned as:
I am looking for a Route like /api/invoices?subscriptionId=x,y,z
You can do couple of things:
pass the subscriptionIds one after the other separated by & in the query string of the URL and change the input parameter of action method to accept array of subscriptionIds
example of route:
/api/invoices/find?subscriptionId=x&subscriptionId=y&subscriptionId=z
example of action method parameter accepting array of subscriptionIds:
public IEnumerable<InvoiceViewModel> Find([FromQuery]long[] subscriptionId)
pass the comma separated string as querystring in the URL and write a piece of logic in the action method to split the string based on comma to get an array of subscriptionIds
example of route:
/api/invoices/find?subscriptionIds=x,y,z
example of action method:
public IEnumerable<InvoiceViewModel> Find([FromQuery]string subscriptionIds)
{
var ids = subscriptionIds.Split(',').Select(int.Parse).ToArray();
// do the logic on multiple subscriptionIds
}
Apart from this, you can go for creating custom model binders as well as suggested in other answers.
Hope this helps.
There can be many ways to achieve this task (I can think of two-three for now).
1) instead of long subscriptionid take a string as an input and validate it before proceeding further.
[HttpGet]
public IEnumerable<InvoiceViewModel> Find(string subscriptionIds)
{
var list = validateInput(subscriptionIds);
var invoiceList = _invoiceManager.FindList(list);
...
return invoiceViewModels;
}
public IList<long> validateInput(string subscriptionIds)
{
var list = subscriptionIds.Split(",");
... // Code to convert each element in long and throw if it is not long
return longlist;
}
2) Create custom model binders.
Steps are mentioned here:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
=> [FromUri] attribute can be used to bind the Complex types from query string parameters but i am not sure how i would use that.
If you ask me, i would go for approach-1 (not to increase complexity).
You can create a specific Request view model which accepts a collection of invoice ids:
public class InvoiceRequestModel
{
IEnumerable<long> InvoiceIDS { get; set; }
}
and use it for your action method:
[Route("tenants/{tenantId:long}/subscriptions/{subscriptionId:long}/invoices")]
[HttpGet]
public IEnumerable<InvoiceViewModel> Get(InvoiceRequestModel requestModel)
{
}
In the case you want to use query parameters, mark your action parameter with the [FromQuery] attribute:
[Route("tenants/{tenantId:long}/subscriptions/{subscriptionId:long}/invoices")]
[HttpGet]
public IEnumerable<InvoiceViewModel> Get([FromQuery]IEnumerable<long> invoiceIDs)
{
}
and on creating the request, pass each value with the same key in the query string:
invoiceIDs=1&invoiceIDs=2&invoiceIDs=3
Finally, it will look like this:
tenants/{tenantId}/subscriptions/{subscriptionId}/invoices?invoiceIDs=1&invoiceIDs=2&invoiceIDs=3

return decimal value in web api

I have following method in repository project , and I'm trying to get that value via web api,
Method
public decimal findBookPrice(int book_id)
{
var bookprice = (
from r in context.Books
where r.Book_Id == book_id
select r.Price
).FirstOrDefault();
return bookprice;
}
Book Class
public class Book
{
[Key]
public int Book_Id { get; set; }
[Required]
public string Book_Title { get; set; }
[DataType("decimal(16 ,3")]
public decimal Price { get; set; }
...
}
}
Web API method
// GET: api/BookPrice/3
[ResponseType(typeof(decimal))]
public IHttpActionResult GetBooksPriceById(int id)
{
decimal bookprice = db.findBookPrice(id);
return Ok(bookprice);
}
but once I direct to url which is http://localhost:13793/api/BookPrice/2
I'm getting following output not the decimal value
The shown error message is caused by a routing problem. The ASP.NET MVC framework was not able to find the right controller or action for the URL
http://localhost:13793/api/BookPrice/2
The default routing rule in ASP.NET MVC takes BookPriceand tries to find the BookPriceController. As you stated in your comment, the action is in a BooksWithAuthersController. Therefore the URL has to be (if you want to use the default routing rule):
http://localhost:13793/api/BooksWithAuthers/2
Have a look at article if you want to read more about this topic.
EDIT:
Looking at the whole controller code you will find the two action methods called GetBooksWithAuthersById and GetBooksPriceById. Because both start with get and have got the same parameter list (int id), the ASP.NET MVC framework has got two possible action methods for the URL /api/BooksWithAuthors/2. To solve this ambiguity you can give the GetBooksPriceById action a separate route via the [Route] annotation.
Like in this slightly adjusted BooksWithAuthersController:
public class BooksWithAuthersController : ApiController
{
[ResponseType(typeof(BookWithAuther))]
public IHttpActionResult GetBooksWithAuthersById(int id)
{
...
}
[ResponseType(typeof(decimal))]
[Route("api/bookswithauthers/{id}/price")]
public IHttpActionResult GetBooksPriceById(int id)
{
...
}
}
In order get the price of a book, the URL http://localhost:13793/api/BooksWithAuthers/2/price will return the decimal value.

ASP.NET Web API model binding non-sequential list of complex objects

I am attempting to model bind a complex object with a non-sequential list using an ApiController. All of the fields except the list are set correctly, but the list contains one element (even though two list elements were posted) and the element is null. If I take the exact same code and point it to an MVC Controller using the same parameter type in my action method, everything works as expected.
Since I am using a non-sequential list, I am using the hidden ".Index" input as described by Phil Haack (http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx)
The ApiController also binds the list correctly if I remove the ".Index" input and send the list as a sequential list starting at 0. (This option work for testing, but is not a great option in production as the list items can be added and removed by the user, which is why I want to use the non-sequential list.)
I understand that Web API Controllers do parameter binding differently than MVC Controllers as discussed here, but it seems like non-sequential lists should bind correctly in Web API Controllers. Am I missing something? Why does the same code work for an MVC Controller and not a Web API Controller? How can I get non-sequential lists to bind correctly in Web API?
Here are my Post parameters:
Parameters application/x-www-form-urlencoded
BatchProductLots.Index 1
BatchProductLots.Index 2
BatchProductLots[1].BrandId 1
BatchProductLots[1].ContainerId 9
BatchProductLots[1].ContainerLot 123
BatchProductLots[1].PackageId 2
BatchProductLots[1].PlannedQuantity 0
BatchProductLots[1].ProducedQuantity 20
BatchProductLots[2].BrandId 1
BatchProductLots[2].ContainerId 9
BatchProductLots[2].ContainerLot 123
BatchProductLots[2].PackageId 1
BatchProductLots[2].PlannedQuantity 0
BatchProductLots[2].ProducedQuantity 1
BatchStatusId 1
LotNumber 070313
ProductionDate 07/03/2013
RecipeId 1
RecipeQuantity 1
SauceId 22
X-Requested-With XMLHttpRequest
Here is my Web API Controller Action:
(request.BatchProductLots list is set to one element (even though two elements were posted) and that one element is null)
public Response Create(BatchCreateRequest request)
{
Response response = new Response();
try
{
Batch batch = Mapper.Map<Batch>(request);
batchService.Save(batch);
response.Success = true;
}
catch (Exception ex)
{
response.Message = ex.Message;
response.Success = false;
}
return response;
}
Here is the complex object with the list that I am attempting to bind to:
public class BatchCreateRequest
{
public int BatchStatusId { get; set; }
public DateTime ProductionDate { get; set; }
public string LotNumber { get; set; }
public int SauceId { get; set; }
public int RecipeId { get; set; }
public int RecipeQuantity { get; set; }
public List<BatchProductLot> BatchProductLots { get; set; }
public class BatchProductLot
{
public int BrandId { get; set; }
public int ContainerId { get; set; }
public string ContainerLot { get; set; }
public int PackageId { get; set; }
public int PlannedQuantity { get; set; }
public int ProducedQuantity { get; set; }
}
}
Short answer, it's not possible using Web Api's Model Binder. MVC and Web Api use different model binders and the Web Api model binder only works on simple types.
See this answer for links that explain further as well as possible solutions.
Longer answer, create a custom implementation of System.Web.Http.ModelBinding.IModelBinder and change your Action's signature to the following
public Response Create([ModelBinder(CustomModelBinder)]BatchCreateRequest request)
Do you really need Index to be set? In that case, one possible solution could be to make Index part of the BatchProductLot class. The sequence of list won't matter then and Web Api should be able to bind it.
Another idea would be to use application/json content type and send JSON. You can use Json.Net to deserialize and model binding would work.
Read Using an alternate JSON Serializer in ASP.NET Web API and even use this Nuget Package WebApi Json.NET MediaTypeFormatter if you don't want to do the hand wiring.

Can ServiceStack services contain multiple methods?

Environment is Visual Studio 2012, ServiceStack, ASP.NET Web Application Project (followed https://github.com/ServiceStack/ServiceStack/wiki/Create-your-first-webservice)
Looking through some of the classes in ServiceStack.Examples, I noticed that most of the services contain only one method. Either some override on Execute() or, if a REST service, some override of OnPost/Get/Put/Delete().
How should I approach making a full API set, if I have tens of functions I need implemented RegisterUser(), RemoveUser(), AddFriend(), RemoveFriend() ... One service per method?
public RegisterUserService : IService<User> { public object Execute(User> dto) { ... } }
public RemoveUserService : IService<User> { public object Execute(User> dto) { ... } }
public AddFriendService : IService<Friend> { public object Execute(Friend dto) { ... } }
public RemoveFriendService: IService<RequestDTO4> { public object Execute(Friend dto) { ... } }
I'm pretty lost on how to begin implementing a full API set. I've read the first and second wiki page on 'Creating your first webservice', which I've copied to make 1 service method. But now I want to make 10 or 40 service methods and I'm not sure how to do that.
I noticed that implementing from IRestService<T> allows you up to 4 methods instead of the one Execute() method, simply because each method corresponds to a different HTTP verb. So is there something like that I could write? Basically something like:
public MyService : IService/IRestService/ServiceBase?<User>
{
public object AddUser(User user) { }
public object RemoveUser(User user) { }
public object ModifyUser(User user) { }
}
Just looking for something that doesn't necessarily have to contain all methods in one service class, but as many as reasonably possible ... do I really have to create 1 service for each service method?
Note on pursuing a strictly RESTful architecture: I only read up a little on REST, but it seems like I'd have to strictly follow rules like: treat everything as a resource even if you have to re-design your models, no verbs in the URL names (/Friends, not /GetFriends because REST gives you OnGet(), OnPost(), OnPut(), and OnDelete() ... basically I'm interested in the easiest, quickest, and most painless way of implementing a a few dozen service methods. It's a personal project, so the requirements won't vary too much.
Thanks in advance for guiding me through this first step.
EDIT: Just saw this related question: How to send commands using ServiceStack?
Mythz said there's no "ServiceStack way" to design. The guy's question is pretty much like mine. I'm wondering how to stack a lot of service methods in a service.
EDIT 2: Just saw Need help on servicestack implementation, and Separate or combined ServiceStack services?.
I just tested the code below successfully with working routes:
[Route("/registerUser/setEmail/{Email}")]
[Route("/registerUser/setPassword/{Password}")]
[Route("/registerUser/setPhoneNumber/{PhoneNumber}")]
[Route("/lalal2395823")]
[Route("/test3234/test23423511")]
public class RegisterUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Nickname { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
But what I'd like is for each [Route("path")] to go to a different method, instead of having them all parsed in Execute() and having to parse which string isn't null or empty.
My Solution
I decided to take Rickard's advice and make a proper REST API, because it seems simpler and cleaner in the end.
This is now my class using the new ServiceStack API (new as of 9/24/12):
using UserModel = Project.Model.Entities.User;
[Route("/User", "POST")]
[Route("/User/{FirstName}", "POST")]
[Route("/User/{FirstName}/{LastName}", "POST")]
[Route("/User/{FirstName}/{LastName}/{Nickname}", "POST")]
[Route("/User/{FirstName}/{LastName}/{Nickname}/{PhoneNumber}", "POST")]
[Route("/User/{FirstName}/{LastName}/{Nickname}/{PhoneNumber}/{Email}", "POST")]
public class CreateUser : IReturn<UserModel>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Nickname { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class CreateUserService : Service
{
public object Post(CreateUser request)
{
try
{
using (var session = FluentNHibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var user = new UserModel()
{
FirstName = request.FirstName,
LastName = request.LastName,
Nickname = request.Nickname,
PhoneNumber = request.PhoneNumber,
Email = request.Email,
Password = request.Password,
};
session.SaveOrUpdate(user);
transaction.Commit();
return user;
}
}
}
catch
{
throw;
}
}
}
This is now a lot simpler with ServiceStack's new API Design released in (v3.9.15+).
#Rickard makes a lot of good points on how to re-structure your service so it's more REST-ful which is now easier to achieve with ServiceStack's new API which is now less restrictive and more flexible where the same service can handle multiple different Request DTOs and you're no longer restricted in the Response Type you can return.
Following the HTTP way you have to turn your way of thinking upside down. You need to think in terms of resources, i.e. users, friends, etc. Using HTTP you already have a finite set of methods, namely Get, Put, Post, and Delete.
Hence, the service API design could look like this:
RegisterUser() => POST /users
RemoveUser() => DELETE /users/{userid}
AddFriend() => POST /users/{userid}/friends
RemoveFriend() => DELETE /users/{userid}/friends/{friendid}
ModifyUser() => PUT /users/{userid}
etc.
To implement for example RemoveFriend in ServiceStack you could do like this:
public class UserFriendService : RestServiceBase<UserFriendRequest>
{
public override object OnPost(UserFriendRequest request)
{
// pseudo code
var user = GetUser(request.UserId);
var friend = GetUser(request.FriendId); // FriendId is a field in the HTTP body
user.Friends.Add(friend);
return HttpResult.Status201Created(user, ...);
}
//...
}
[Route("/users/{userId}/friends")]
public class UserFriendRequest
{
public string UserId { get; set; }
public string FriendId { get; set; }
}

Accessing custom objects in DomainService from client

I am using Domain Service to fetch data from database from Silverlight Client.
In DomainService1.cs, I have added the following:
[EnableClientAccess()]
public class Product
{
public int productID;
public string productName;
public List<Part> Parts = new List<Part>(); //Part is already present in Model designer
}
In DomainService1 class I added a new method to retrive a collection of the custom class object:
[EnableClientAccess()]
public class DomainService1 : LinqToEntitiesDomainService<HELPERDBNEWEntities1>
{
...
public List<Product> GetProductsList(...)
{
List<Product> resultProducts = new List<Product>();
...
return resultProducts;
}
}
From the silverlight client I am trying to access that method:
DomainService1 ds1 = new DomainService1();
var allproductList = ds1.GetProductsList(...);
ds1.Load<SLProduct>(allproductList).Completed += new EventHandler(Load_Completed); //Not correct usage
However it is not the correct way to call the new method. The reason I added a new class Product in DomainServices.cs is to have an efficient grouping. I cannot achieve the same using the model classes auto-generated by the entity framework.
How call I call the new method from the client?
I believe there is a similar question with an answer here:
Can a DomainService return a single custom type?
Also, here is some discussion about the overall problem of adding custom methods in a Domain Service:
http://forums.silverlight.net/t/159292.aspx/1
While I don't know what you mean by "it is not the correct way to call the new method", or if you're getting any errors, I thought maybe posting some working code might help.
My POCO
public class GraphPointWithMeta
{
[Key]
public Guid PK { get; set; }
public string SeriesName { get; set; }
public string EntityName { get; set; }
public double Amount { get; set; }
public GraphPointWithMeta(string seriesName, string entityName, double amount)
{
PK = Guid.NewGuid();
SeriesName = seriesName;
EntityName = entityName;
Amount = amount;
}
// Default ctor required.
public GraphPointWithMeta()
{
PK = Guid.NewGuid();
}
}
A method in the domain service (EnableClientAccess decorates the class)
public IEnumerable<GraphPointWithMeta> CallingActivityByCommercial()
{
List<GraphPointWithMeta> gps = new List<GraphPointWithMeta>();
// ...
return gps;
}
Called from the Silverlight client like
ctx1.Load(ctx1.CallingActivityByCommercialQuery(), CallingActivityCompleted, null);
client call back method
private void CallingActivityCompleted(LoadOperation<GraphPointWithMeta> lo)
{
// lo.Entities is an IEnumerable<GraphPointWithMeta>
}
I am not sure if your Product class is an actual entity or not. From the way it is defined, it does not appear to be an entity. My answer is assuming it is not an entity. You will need to apply the DataMemberAttribute for your Product properties, and you wouldn't load the product list - load is for Entity Queries (IQueryable on the service side). You would just invoke it like this (client side):
void GetProductList( Action<InvokeOperation<List<Product>>> callback)
{
DomainService ds1 = new DomainService();
ds1.GetProductsList(callback, null);//invoke operation call
}
And the domain service's (server side) method needs the InvokeAttribute and would look like this:
[EnableClientAccess]
public class MyDomainService
{
[Invoke]
public List<Product> GetProductList()
{
var list = new List<Product>();
...
return list;
}
}
And here is how your Product class might be defined (if it is not an entity):
public class Product
{
[DataMember]
public int productID;
[DataMember]
public string productName;
[DataMember]
public List<Part> Parts = new List<Part>(); // you might have some trouble here.
//not sure if any other attributes are needed for Parts,
//since you said this is an entity; also not sure if you
//can even have a list of entities or it needs to be an
//entity collection or what it needs to be. You might
//have to make two separate calls - one to get the products
//and then one to get the parts.
}
Like I said, i am not sure what Product inherits from... Hope this helps.

Categories

Resources