how to search other field than id - c#

I'm following and implementing a side project from:
https://learn.microsoft.com/es-mx/aspnet/core/tutorials/first-web-api?view=aspnetcore-3.0&tabs=visual-studio
But in the part where [HttpGet("{id}")] is invoked, it works only with the id field, but I want to retrieve a JSON stored in the DBmemory, with other field instead of id; in this case I want to manage data by field TAG.
How can I accomplish this?
I've try to change all the id parts to TAG, which is the field I'm looking for, but when I do this, the post method breaks up.
// GET: api/Maquinas/5
[HttpGet("{id}")]
public async Task<ActionResult<Maquina>> GetMaquina(string id)
{
// HERE. i need to find data with the field of "TAG" not "id"
var maquina = await _context.Maquinas.FindAsync(id);
if (maquina == null)
{
return NotFound();
}
return maquina;
}

Don't get stuck on the fact that is called id. You could make use of this endpoint and instead of passing the value of id to pass the value of tag, api/Maquinas/tagvalue.
Later on you should use this value in the call you make to retrieve the entity you are looking for.
_context.Maquinas.FirstOrDefaultAsync(maquina => maquina.Tag == id);
I have assumed here that the property on which you want to filter is called Tag and it's type is string. It is quite probable, at least the name of the property to not be this one. So you have to change the above code correspondingly.
This will fix your problem, but you should not consider this a best practice. The semantics of your API would be broken. The very reason, I shared the above, is to show you that the name of the parameter id is irrelevant with that you pass. There isn't any check that would halt you for passing there "anything". The reason I wrote that the semantics of your API would be broken is that since this is going to be a REST api, someone would expect an endpoint like the following one:
api/Maquinas/1
for getting the entity with id 1.

Related

How do I update a MongoDB document but exclude a specific field?

I am creating a web API. I need something like this:
When I updating a document at mongodb, I do not want to update a field (createdAt). I know that I can get a old value of that field and manuelly and then put it updated object but it requires one more unnecessarry request to db. I do not want this. My method is here:
public async Task<bool> UpdateAsync(Customer updatedCustomer)
{
var result = await _mongoService.Customers.ReplaceOneAsync(c => c.Id == updatedCustomer.Id, updatedCustomer);
return result.IsModifiedCountAvailable && result.ModifiedCount>0;
}
Is there any way to exclude one property of my Customer class (createdAt) and left it same everytime. BTW please do not recomend that set all properties update one by one by using "Set" method. Thank you.
I'm not sure if there is a way other than to set the properties one by one, but researching the following may be helpful or suggestive of something new.
In Mongodb you can use some decoration to do like [BsonIgnore] but it will ignore it every time
One alternative would be to load the document you wish to modify, followed by calling BsonDocument.Merge with overwriteExistingElements set to true in order to merge your changes.

issue updating an Api value in c# asp.net [duplicate]

This question already has answers here:
How to update only one field using Entity Framework?
(17 answers)
Closed 8 years ago.
Hey guys I am curious in how I can update just one column at a time in a database. When I run something such as postman or fiddle to query a Put to my database. If I only include one field, it sets all of the other fields = to null. Is there anyway I would be able to leave the other fields blank when I query the PUT and it will only change the one field I am asking the PUT to update? Sorry if my explanation is not good I am new to using API's.
Here is my PUT method (basic scaffold):
public IHttpActionResult PutUser(int id, User user)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != user.Id)
{
return BadRequest();
}
db.Entry(user).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!UserExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
When I want to update, say just the first name, and there is already a first and last name in the database. After the PUT method the last name would be set to null. So I debugged and noticed that the user it is taking in in the parameter already has last name set to null. Any advice would be greatly appreciated!
I'm guessing that you are sending a blank user with just information in the column that you want to update. Well what you should do is read the user details first, then change the column/field as required, then send this new user object back to the API Put method
Edit
Basically you can't really specify a single column/field to update using this API pattern. Look at your constructor, there's no parameter to tell the code which column you want to update. (You could test for nulls, but I would strongly advise against it). Your code is telling EntityFramework to update the database with the User object that you provide.
Therefore you need to first retrieve the user that you want to update (using a GET), and only change the field that you want to change, then send the updated User object back to the API Put method. If you send a User object with NULL values, then these NULL values will be saved to the database.
If you really want to be able to specify columns, you can write separate PUT method overloads that will only update the column you want. However programming this way requires more effort and more maintenance, and I would advise against it.

Explicit vs. implicit null in ASP.NET Web API during partial updates

I have been experimenting with Web API 2 for the past couple of weeks and I'm trying to figure out the best way to handle a particular scenario during partial updates.
The API will allow the user to do partial updates via POST. By design, any properties that are not supplied in the request body are assumed to be unchanged and no changes will be made to those properties.
The challenge, however, is trying to determine when a user has explicitly set a property value to null. When the request body is pulled in via the controller, any absent properties are set as null automatically as the JSON request body is deserialized. As such, I lose my ability to determine if the property value is null explicitly (i.e. the user is trying to set the property value as null, in which case I want to update the property to null) or if the property value is null implicitly (i.e. the property value was set to null during deserilaization, in which case I want to ignore it).
I am looking for any ideas of how I might approach this situation.
I have played around with this a bit and I have come up with a way to work around this. Maybe there's another way to address the issue but this seems to be a reasonable approach:
In Web API, the request body can only be read once. Therefore, if you have the controller pull the object in for you, the object will be deserialized and you will lose access to the original request content and will not be able to determine if something was explicitly null or absent. This is demonstrated by something like this:
[Route("cars"), HttpPost]
public IHttpActionResult AddCar(Car car)
{
Car newCar = Car.Add(car);
return Created<Car>("/cars/" + newCar.car_id, newCar);
}
If you want to be able to examine exactly what was sent in, you don't have the controller pull in the object for you, instead, you pull the request body in manually, thus preserving your ability to see exactly what was sent in, like this:
[Route("cars"), HttpPost]
public IHttpActionResult AddCar()
{
HttpContent content = Request.Content;
string carJson = content.ReadAsStringAsync().Result;
// You now have the original JSON and can examine it before deserialization
}
It certainly adds a few more steps, but at least in my case where I needed to be able to see exactly what was POSTed, this provides a solution that seems to work.

Querying C# attribute

i have tried to surf the internet but i could not get anything related to what i want.
This is in relation to ASP.Net. But could be any other instance as well.
Following is my attribute
class SomeAttribute :Attribute
{
string someparam;
string SomeParam
{
get{ return someparam;}
set { someparam = val;}
//the value generated for someparam is dynamically generated with respect to some attribute present in the request header.
}
}
it's similar to the [Authorize] attribute that .net uses in its asp .net memberships to validate if the user has logged in and it redirects him back to log in page if validation fails.
I have an attribute associated with a method like below:
[SomeAttribute]
public void someFunction
{
//i want to retrieve here the value of someparam jus generated before entering this method.
}
Note that i don't pass any value or used any named properties in this attribute. It is simply going to check a condition for me whenever the method is called and return true or false and accordingly the function is either called or not.
In my case, After validating, it generates a value and that value has to be shared with the function to which it is associated 'somefunction'.
i know reflections can help me get the attributes associated with a function and the value of its properties.
But here i dont want to fetch the value from some other function. And i dont want to just fetch the attribute either.
As i mentioned earlier when the function is called the attribute will work upon that. What the attribute does is fetches some data from request header and does some processing and generates a value. Now this value has to be passed on to the function just after that.
Well, what you want to accomplish is certainly possible, but it would not be an optimal use of the run-time or the MVC model.
In this particular case, think of an attribute as an annotation. It's something you use to mark a function, controller, etc. so that its execution behaves differently at run-time. The attribute itself should not be doing the bulk of the work, rather just signalling to other pieces in your design to behave differently.
It seems like you want to check some header values, and calculate something based off of that. You can use extension methods off of a Request class to accomplish this.
Now, let's say that inside your Controller's function, you want to guarantee that the header values exist. You can have an attribute called RequireHeaderValues that implements IActionFilter. The attribute would check the header for the required values and if they don't exist, it routes the response to another location or somehow indicates error. This way, when inside your function, you call the extension method off the Request object, you are guaranteed that the values will exist. The MVC run-time will automatically call your filter attribute for you. For more info, see this.

Passing model from a post method to a new get method in MVC

I have an application.
I am stuck at a point from where i want to pass a model from a Post method to a Get method.
// Code in get method
FoundAccounts fa=new FoundAccounts();
fa.register = model;
return RedirectToAction("FoundAccounts", fa);
//Post Method
public ActionResult FoundAccounts(FoundAccounts fa)
{
//Use that values here
}
Can i do it like this?
I am unable to find a way.
Please help me with the same.
Thanks
Can i do it like this?
No, you can't. You can only pass simple, scalar properties to the route values of a RedirectToAction call. It doesn't make sense to pass complex objects, because when you perform a redirect, only the simple properties will be included in the GET request as query string parameters.
So you have different possibilities:
Persist the entity in your backend and then pass only the id to the GET action (this is the solution I recommend):
int id = repository.Save(fa);
return RedirectToAction("FoundAccounts", new { id = id });
and then your GET action will take the id as action parameter and use this id to retrieve the entity from wherever you persisted it initially:
public ActionResult FoundAccounts(int id)
{
FoundAccounts model = repository.Get(id);
...
}
Pass all properties and leave the model binder dehydrate the entity in the GET action:
return RedirectToAction("FoundAccounts", new
{
prop1 = fa.prop1,
prop2 = fa.prop2,
...
});
Obviously here if you have some complex properties you will need to pass them as well. Remember that the properties you include will be the properties you will be able to retrieve in your GET action. Everything else will be lost:
return RedirectToAction("FoundAccounts", new RouteValueDictionary
{
{ "prop1.SubComplexProp1", fa.prop1.SubComplexProp1 },
{ "prop1.SubComplexProp2", fa.prop1.SubComplexProp2 },
{ "prop2", fa.prop2 },
});
The drawback of this solution is that if you have lots of properties this could quickly become cumbersome. And you could even hit on a roadblock because there's a limitation to the size of a GET request. This limitation will vary between browsers, but I wouldn't pass anything more than 2048 characters in a GET request.
Use Session or TempData (not recommended as it introduces state into your application);
TempData["fa"] = fa;
return RedirectToAction("FoundAccounts");
and then inside the GET action retrieve the model from the Session or TempData:
public ActionResult FoundAccounts()
{
FoundAccounts model = TempData["fa"] as FoundAccounts;
...
}
The difference between Session and TempData is that TempData will survive only for a single redirect and will then be automatically evicted by the framework. Under the covers it uses Session, it's just that it is automatically cleared once you read the value in the GET action. The problem with this of course is that if the user hits F5 to refresh the page in his browser, you will no longer find the value in TempData because it was evicted. Even worse if the user decides to bookmark the GET action, he will have the same problem if later he decides to come back and navigate to this bookmark. So people tend to use Sessions for those kind of things. Sessions of course do not solve the problem with bookmarks (because the user could have closed his browser in-between and the Session will be lost). Also Sessions introduce other problems in web farm scenarios. For example if the session is stored in-memory (which is the default), this means that you could store the value on one node of the farm but when you perform the redirect you could hit another node of the farm and then this node no longer has any knowledge of the session. So people start to use an out-of-process sessions - either stored in a State Service machine or SQL service. But what's the point? I mean take a look at my first and recommended solution. It's exactly what you will end up a fortiori if you want to have scalable solution working in a web farm environments.

Categories