How to use Postman for FromUri request parameters? - asp.net-web-api2

I have written the below simple Web API method.
[HttpGet]
[HttpPost]
public int SumNumbers([FromUri]Numbers calc, [FromUri]Operation op)
{
int result = op.Add ? calc.First + calc.Second : calc.First - calc.Second;
return op.Double ? result * 2 : result;
}
Below is the model class for Numbers:
public class Numbers
{
public int First { get; set; }
public int Second { get; set; }
}
Below is the model class for Operation:
public class Operation
{
public bool Add { get; set; }
public bool Double { get; set; }
}
Now, I am not understanding how to use Postman to check this Web API method.
I have tried like below, but not working. I am not getting any error, but I am not getting response. Can anyone help me?

You're setting the values on the header but using the URI in your code. You would need either to change your code OR the way you send the request with Postman.
As far as I can see you'd need to add the values to your URI as part of the query string:
http://localhost:29844/api/bindings/SumNumbers?first=10&second=20&add=true&double=false
Have a look at this

Related

.Net 5 - API JsonProperty

I have a [HttpPost] function in API Controller, that has this definition:
public async Task<IActionResult> Test([FromBody] TestData testData)
I tried to use many atributes anotations in my class TestData [JsonProperty("")], [JsonPropertyName("")], [JsonObject].
I used libraries - Newtonsoft.Json and System.Text.Json.Serialization. But the testData always included null. The API works when I put a body with same name of atribute has. Soo I expect, I am missing something in my Configuration.
I even try to add services.AddControllersWithViews().AddNewtonsoftJson() . Nothing changed.
How does it make it work in .Net 5 ?
#jps
public class TestData
{
[JsonIgnore]
public int Id { get; set; }
[JsonIgnore]
public string UserId { get; set; }
[JsonPropertyName("test_number")]
public long Number { get; set; }
...
}
When I post a body {"test_number":"123456"} on http://.../Test . I see testData.Number = null
I feels like, the JsonPropertyName works only for Serialization , and not for
Deserialization
Solved, There was an issue with Docker.

Map GET request to Action

I'm trying to validate the progress quantity (and other fields once this works) that belongs to the BeginCollectionItems server side. The request is being sent but the parameter progressQty is not being read by the action.
This is the action I'm trying to map to:
[AllowAnonymous]
[AcceptVerbs("Get", "Post")]
public IActionResult CheckValidProgressQty(int progressQty)
{
int a =progressQty;
var result = false;
if (a > 0)
result = true;
return Json(result);
}
This is the request:
:method: GET
:path: /Components/CheckValidProgressQty?ProgressItems%5B16bad1f2-155c-4a29-844c-34e88da80b7c%5D.ProgressQty=-300
This is the Query String Parameters:
ProgressItems[16bad1f2-155c-4a29-844c-34e88da80b7c].ProgressQty: -300
Here is the remote validation in the View Model Class:
[Remote(action: "CheckValidProgressQty", controller: "Components", HttpMethod ="GET", ErrorMessage = "BAD QTY!")]
public int ProgressQty { get; set; }
Right now it goes into the CheckValidProgressQty method but I'm just not able to access the progressQty parameter. One way I can access is:
Request.QueryString.Value
?ProgressItems%5B16bad1f2-155c-4a29-844c-34e88da80b7c%5D.ProgressQty=-8
and parse it. But I think there should be something more simple available.
ProgressItems[16bad1f2-155c-4a29-844c-34e88da80b7c].ProgressQty: -300
This is posted form data when you do POST method not for GET method.
You could not get the query string on your action parameters using ?ProgressItems%5B16bad1f2-155c-4a29-844c-34e88da80b7c%5D.ProgressQty=-300since they are not match.
Refer to my below demo which introduces how to pass querystring to action, assume that I have models:
public class TestUser
{
[Key]
public int Id { set; get; }
public string Name { get; set; }
public IList<UserInterest> Interests
{
get; set;
}
}
public class UserInterest
{
[Key]
public int Id { set; get; }
[Required]
public string InterestText { set; get; }
public int Option { set; get; }
}
You need to use an object like
public ActionResult UserTest(TestUser model)
And the querystring is ?Interests[0].InterestText=hello

.NET CORE API: Is it possible to conditionally validate a model depending on the http verb used to submit it?

I'm very new to the FluentValidation and I'd like to validate my model in different ways depending on which verb was used to submit it.
Given a very simple class, I'd like to ignore the ID property on a POST but ensure it's been provided on a PUT. Is this something the FluentValidation can do?
public class CategoryModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I'm guessing I have to get the HttpContext over to the validators so I can determine the http method used, but I don't want to re-invent the wheel if there's already a built-in way.
Thanks!!
I think I've come up with a solution by passing the context to my validator. However, if something looks wrong or out of place, please let me know.
public class CategoryModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class CategoryModelValidator : AbstractValidator<CategoryModel>
{
public CategoryModelValidator(IHttpContextAccessor context)
{
if (context.HttpContext.Request.Method == HttpMethods.Post)
RuleFor(x => x.ID).Empty();
if (context.HttpContext.Request.Method == HttpMethods.Put)
RuleFor(x => x.ID).NotEmpty();
RuleFor(x => x.Name).Length(1, 30);
}
}
Passing the context was easier than I thought. All I had to do was register it in my ConfigureServices method with services.AddHttpContextAccessor() and DI takes care of the rest.
To be honest, this is a pretty handy validation tool

Sending byte array to API

I am converting web application to mobile app. We were using AjaxAsyncFileUpload in web application to save a document to the server, where AjaxAsyncFileUpload use to do the work for me. This was the code
Dim fileData As Byte() =new Byte(AjaxAsyncFileUpload.FileContent.Length-1){}
AjaxAsyncFileUpload.FileContent.Read(fileData, 0, fileData.Length)
InvestmentDeclare.DocSize = AjaxAsyncFileUpload.FileContent.Length
InvestmentDeclare.DocFileName = AjaxAsyncFileUpload.FileName
InvestmentDeclare.DocFileType = AjaxAsyncFileUpload.PostedFile.ContentType
InvestmentDeclare.Document = fileData
And then simply save this to my database.
Now while Converting this to mobile app (I am also using c# for mobile app), I am not able to pass the byte array. I am using fiddler for testing.
I have attached an image of how I'm passing it through fiddler. In my API POST method I'm getting a null value to my document variable while I'm able to get rest of my values properly.
What could be the issue? Am I not passing the byte in proper Json format?
In API:
public class AddInvestmentDeclare
{
public int EmployeeId { get; set; }
public int YearId { get; set; }
public int InvestmentId { get; set; }
public List<EmpDocument> EmpDocuments { get; set; }
}
public class EmpDocument
{
public byte[] Document { get; set; }
public string DocumentFileName { get; set; }
public long DocumentSize { get; set; }
public string DocumentType { get; set; }
}
public HttpResponseMessage Post(int YearId, [FromBody]List<AddInvestmentDeclare> InvestmentDeclared)
{
When I check my InvestDeclared list on run time I see that document variable is not filled and it is showing null. I have attached an image of that as well.
First, setup your API method in a way that it accepts just one object containing all data instead of each parameter individually.
Instead of:
public HttpResponseMessage Post([FromUri]string AccordDbName, [FromUri]String PayCareDbName, [FromUri]...)
Set it up like:
public HttpResponseMessage Post(Data dataObject)
Secondly, try sending file as a base64string.
Here is example how to do it.
Your file in JSON request should look something like this:
{ "ID":46,
"Content":"JVBERi0xLjQNCjEgMCBvYm......"
}

this[propertyName] is not a function in breeze.debug.js

I am using Hot towel template and extended functionality of it by using breeze. I have used breeze.partial-entities.js file to conver breeze entities to proper dtos that can be used by knockout observables as shown below.
function dtoToEntityMapper(dto) {
var keyValue = dto[keyName];
var entity = manager.getEntityByKey(entityName, keyValue);
if (!entity) {
// We don't have it, so create it as a partial
extendWith = $.extend({ }, extendWith || defaultExtension);
extendWith[keyName] = keyValue;
entity = manager.createEntity(entityName, extendWith);
}
mapToEntity(entity, dto);
entity.entityAspect.setUnchanged();
return entity;
}
For few of the entities it is working properly and getting breeze data converted to entities but for one of the entity implementation is failing. Model for the same is given as below.
public class StandardResourceProperty
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int StandardResourceId{ get; set; }
public int InputTypeId{ get; set; }
public int ListGroupId{ get; set; }
public string Format{ get; set; }
public string Calculation{ get; set; }
public bool Required{ get; set; }
public int MinSize{ get; set; }
public int MaxSize{ get; set; }
public string DefaultValue{ get; set; }
public string Comment { get; set; }
public virtual StandardResource AssociatedStandardResource { get; set; }
public virtual List AssociatedList { get; set; }
}
The error i am getting is
TypeError: this[propertyName] is not a function
[Break On This Error]
thispropertyName;
breeze.debug.js (line 13157)
]
with code
proto.setProperty = function(propertyName, value) {
this[propertyName](value);
// allow set property chaining.
return this;
};
Please let me know . What can be possible issue with the implementation also , it would be great if i can get more suggestion on how to debug and trace such issues.
Let's back up. I do not understand what you mean by "convert breeze entities to proper dtos that can be used by knockout observables". Breeze entities are already configured as KO observables (assuming you are using the default Breeze model library configuration). What are you trying to do?
I suspect you are following along with the Code Camper Jumpstart course where it does a getSessionPartials projection query. That query (like all projections) returns DTOs - not entities - and maps them with the dtoToEntityMapper method into Session entities.
The CCJS dtoToEntityMapper method cannot be used with entities. It is for converting from a DTO to an Entity and takes DTOs - not entities - as input.
Goodbye to dtoEntityMapper
The dtoToEntityMapper method pre-dates the ability of Breeze to automate projection-to-entity mapping by adding .toType('StandardResourceProperty') to your projection query.
Here is what the CCJS getSessionPartials query could look like now:
var query = EntityQuery
.from('Sessions')
.select('id, title, code, speakerId, trackId, timeSlotId, roomId, level, tags')
.orderBy(orderBy.session)
.toType('Session');
If you go this way, be sure to set the default state of the isPartial flag to true in the custom constructor (see model.js)
metadataStore.registerEntityTypeCtor(
'Session', function () { this.isPartial = true; }, sessionInitializer);
Note that this.isPartial = true is the reverse of the CCJS example where the default was false.
Make sure that you set isPartial(false) when you query or create a full entity. In CCJS there are two places to do that: in the success-callback of getSessionById AND in createSession which would become:
var createSession = function () {
return manager.createEntity(entityNames.session, {isPartial: false});
};