CreateDocumentQuery() with property other than id - linq

I am trying to query document using property other than id in DocumentDB. I found a solution here, but I am not sure what should the URL be when I am doing the query. For example, in this senario:
var families = from f in client.CreateDocumentQuery<Family>(colSelfLink)
where f.Address.City != "NY"
select f;
If it is getFamilyById, it might be http://localhost:50912/api/family/xxxxxx where the xxxxx = family id
If if is getFamilyByCity, it cannot use this format anymore: http://localhost:50912/api/family/xxxxxx where the xxxxx = city name. Because the API would be confused about whether you are choosing a family id or city name. So I think we should use the URL like http://localhost:50912/api/family/byCity/xxxx where xxxx = city name.
But I was wondering how can we achieve this?
Here's my sample code:
namespace Family.Controllers
{
[Produces("application/json")]
[Route("api/Family")]
public class FamilyController : Controller
{
[HttpGet]
public async Task<IEnumerable<Family>> GetAllAsync()
{
var families= await FamilyProfile.DocumentDBRepository<Family>.GetIndividualsAsync(t => t.PrimaryKey != null);
return families;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetByIdAsync(string id)
{
var family= await DocumentDBRepository<Individual>.GetFamilyAsync(id);
if (family== null)
{
return NotFound();
}
return new ObjectResult(family);
}
[HttpGet("{FamilyID}")]
[Route("/ByCity")]
public async Task<IActionResult> GetByCityAsync(string city)
{
var family= await DocumentDBRepository<Family>.GetFamilyAsyncByFamilyID(city);
if (family== null)
{
return NotFound();
}
return new ObjectResult(family);
}
}
}
It returns 404 when I ran http://localhost:50912/api/family/xxxxxx and the break point is not hitting GetByCityAsync(string city). Any suggestions in what I should look into? Thanks!

So I think we should use the URL like http://localhost:50912/api/family/byCity/xxxx where xxxx = city name.
According to your description and code, I suggest that you could modify the Route about GetByCityAsync.
Change
[Route("/ByCity")]
To
[Route("ByCity/{city}")]

Related

There is no argument given that corresponds to the required formal parameter 'photo' of 'Interface.Create(Trademark, IFormFile)'?

I am using .Net Core 5 and uploading images for my Trademark. I use Repository for my work and got error CS706: There is no argument given that corresponds to the required formal parameter 'photo' of 'Interface.Create(Trademark, IFormFile)' in Controller
_trademarkRepo.CreateNewTrademark(trademark);
Controller
public IActionResult CreateTrademark(Trademark trademark)
{
if(ModelState.IsValid)
{
_trademarkRepo.CreateNewTrademark(trademark);
}
_logger.LogInformation("...");
return RedirectToAction("Index");
}
Repo
public bool CreateNewTrademark(Trademark trademark, IFormFile photo)
{
var path = Path.Combine(this._webHostEnvironment.WebRootPath, "trademarks", photo.FileName);
var stream = new FileStream(path, FileMode.Create);
photo.CopyToAsync(stream);
if(CheckExist(trademark.TrademarkName))
{
return false;
}
var newTrademark = new Trademark
{
TrademarkName = trademark.TrademarkName,
Description = trademark.Description,
Image = photo.FileName
};
_dbContext.Trademarks.Add(newTrademark);
_dbContext.SaveChanges();
return true;
}
From error it is evident that what error is.
Method at repo level required two argument. One is trademark and another is photo.
When you have called that from controller , you have only passed one. (Trademark only and photo is missing). This is the error.
Basically your controller should look like following.
public IActionResult CreateTrademark(Trademark trademark,IFromFile photo)
{
if(ModelState.IsValid)
{
_trademarkRepo.CreateNewTrademark(trademark,photo);
}
_logger.LogInformation("...");
return RedirectToAction("Index");
}
Note: There are many other dependencies like how you post file from UI etc. That is not scope of this question and so answer. You have to look for those detail.

Is validating a userId (or any other data extracted from an authentication token) necessary?

In my controller action as have something like this:
[HttpGet]
[ActionName("approve")]
[Authorize(Policy = "Approve")]
public IActionResult GetEntitiesToBeApproved()
{
var stringUserId = User.Claims.FirstOrDefault(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value;
Guid.TryParse(stringUserId, out var userId);
if (userId == default(Guid))
{
return StatusCode((int)HttpStatusCode.BadRequest, ConstantValues.InvalidUserId);
}
//service calls etc.
return Ok();
}
Is there any point in checking that the userId is valid (non-default) or can I skip it?
You can skip it, Authorize filter attribute check it for You.

ASP.NET core HttpGet single Web API

Good Morning,
I’m having difficulty setting up my HTTPGETs and then testing the solution in Postman.
I’m trying to return a single result on both occasions however when I input the parameters nothing loads. So I'm clearly missing something which i need some help on please.
I have 1 parameter {id} in my CashMovementController and if I navigate to localhost/api/cashmovements/{id} it loads however if pass the {id} parameter in postman it fails.
Then in my BondCreditRatingsController I have 2 parameters {ISIN} & {Date} and again I'm not sure how to approach this.
Love to hear some advice/help on this please
Thanks GWS
Startup.cs
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
CashMovementsController.cs
[Route("api/[controller]")]
public class CashMovementsController : Controller
{
private ICashMovementRepository _cashmovementRepository;
[HttpGet("{id}", Name = "GetCashMovement")]
public IActionResult Get(int id)
{
CashMovement _cashmovement = _cashmovementRepository.GetSingle(u => u.CashMovementId == id);
if (_cashmovement != null)
{
CashMovementViewModel _cashmovementVM = Mapper.Map<CashMovement, CashMovementViewModel>(_cashmovement);
return new OkObjectResult(_cashmovementVM);
}
else
{
return NotFound();
}
}
}
BondCreditRatingsController.cs
[Route("api/[controller]")]
public class BondCreditRatingsController : Controller
{
private IBondCreditRatingRepository _bondcreditratingRepository;
public BondCreditRatingsController(IBondCreditRatingRepository bondcreditratingRepository)
{
_bondcreditratingRepository = bondcreditratingRepository;
}
[HttpGet("{id}", Name = "GetBondCreditRating")]
public IActionResult Get(string id, DateTime efffectivedate)
{
BondCreditRating _bondcreditrating = _bondcreditratingRepository.GetSingle(u => u.ISIN == id, u => u.EffectiveDate == efffectivedate);
if (_bondcreditrating != null)
{
BondCreditRatingViewModel _bondcreditratingVM = Mapper.Map<BondCreditRating, BondCreditRatingViewModel>(_bondcreditrating);
return new OkObjectResult(_bondcreditratingVM);
}
else
{
return NotFound();
}
}
If you want to map it to api/Controller/method/id you would need to use the code below because you want to map parameter order (no other identifier) to a specific parameter name in the action.
[HttpGet("GetCashMovement/{id}")]
Your current code should work with below since you are using named parameters and because the request can't be mapped to any other template.
/api/CashMovements/GetCashMovement?id=1
But that attribute syntax will also (possibly unintentionally) trigger:
/api/CashMovements/1
Since a sum of your defined template for that action is:
[Route("api/[controller]/{id}")]
Reason to why /api/ApiTest/GetCashMovement maps GetCashMovement.Get(int i) is because id is defined as optional in startup
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/**{id?}**");
A question mark (?) after the route parameter name defines an optional
parameter.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-3.0#create-routes

How can I pass list of complex objects to webapi from breezejs?

I found that using [fromapi] attribute I can pass one complex object.
when I try to pass list of complex objects it doesn't work.
in the client side I use breeze. server side is webapi.
How can I do this?
You can create one DTO which has property for your list of objects
public class CreateUserDto
{
public string Name {set;get;}
public List<RoleDto> Roles {set;get;}
public CreateUserDto()
{
this.Roles = new List<RoleDto>();
}
}
public class RoleDto
{
public int Id {set;get;}
public string Name {set;get;}
}
And you can use that as the argument of your Web api endpoint
public HttpResponseMesssage Save(CreateUserDto model)
{
//Check model.Roles now
// to do : Return a response
}
From client, you can send data like this.(Assuming you have jQuery library loaded to your page)
var data { Name : "TestName",Roles:[]}
data.Roles.push(new { Id:1,Name:"Admin"});
data.Roles.push(new { Id:2,Name:"Editor"});
$.post("YourEndpointHere",data,function(response){
// do something with response
});
Modelbinding will take care of converting the posted form data to an instance of CreateUserDto in your Save method. You can access model.Roles property to get the list of complex objects you wanted.
you can use Dictionary as below:
[HttpPost]
public IQueryable<Product> GetProducts(Dictionary<string, object> data)
{
var categoryId = Convert.ToInt32(data["categoryId"]);
var category = _context.Categories.Single(a => a.ID == categoryId);
var galleryId = Convert.ToInt32(data["galleryId"]);
var langId = Convert.ToInt32(data["langId"]);
var searchStr = data["str"];
return category.Products.Where(a => a.GalleryID == galleryId, a.LanguageID == langId, a.Description.Contains(searchStr))
}

How do I validate for a empty query string parameter in asp.net mvc3

I want to validate for a empty Id value in the url.
../Task/EditEmployee/afccb22a-7cfd-4be5-8f82-9bd353c13b16
I want that if the Id is empty
../Task/EditEmployee/
Than redirect the user to a certain page.
public ActionResult EditEmployee(Guid Id)
{
//Some code in here
}
It may not be the best solution but you can take id parameter as string and try to parse it like this:
public ActionResult EditEmployee(string id)
{
if(string.IsNullOrWhiteSpace(id))
{
// handle empty querystring
}
else
{
Guid guid;
if (Guid.TryParse(id, out guid))
{
//Some code in here
}
}
}
Or
You can also create a regex constraint on the route but that may be too complicated and hard to understand. Map this route before the default one.
routes.MapRoute(
"TastEditEmployee",
"Task/EditEmployee/{id}",
new { controller = "Task", action = "EditEmployee" },
new { id = #"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$" }
);
Then you can use id parameter as Nullable Guid.
public ActionResult EditEmployee(Guid? id)
{
//do something
}
Since Guid is a struct, the value of Id will be Guid.Empty if it was omitted. You can check for that.
public ActionResult EditEmployee(Guid Id)
{
if (Id == Guid.Empty) throw new ArgumentException("Id not specified.");
}

Resources