Problem with comunication between .Net 6 c# APi and Angular - c#

I have three function in .Net web api in .Net 6.
First:
[HttpPost("name/{name}")]
public async Task<ActionResult<Book>> PostOrder(string name, Book book)
{
try
{
var id = _context.Order.Where(el => el.User == name).Select(el => el.OrderID).FirstOrDefault();
if (id > 0)
{
book.OrderID = id;
_context.Book.Update(book);
await _context.SaveChangesAsync();
return book;
}
else
{
Order o = new()
{
User = name
};
_context.Order.Add(o);
await _context.SaveChangesAsync();
id = _context.Order.Where(el => el.User == name).Select(el => el.OrderID).FirstOrDefault();
book.OrderID = id;
_context.Book.Update(book);
await _context.SaveChangesAsync();
return book;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return NotFound();
}
}
Second and third
[HttpPut("{id}")]
public async Task<IActionResult> PutUser(int id, User user)
{
if (id != user.id)
{
return BadRequest();
}
_context.Entry(user).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!UserExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Users
[HttpPost]
public async Task<ActionResult<User>> PostUser(User user)
{
_context.User.Add(user);
await _context.SaveChangesAsync();
return CreatedAtAction("GetUser", new { id = user.id }, user);
}
And I use to communication Angular:
First:
addToOrder(user: string, book: Book): Observable<Book> {
const url = `${this.orderUrl}/name/${user}`;
return this.http.post<Book>(this.orderUrl, book, this.httpOptions).pipe(
tap(_ => this.log(`added book to order for ${user}`)),
catchError(this.handleError<Book>('addToOrder'))
);
}
Second and third:
updateUser(user: User): Observable<any> {
const url = `${this.usersUrl}/${user.id}`;
return this.http.put(url, user, this.httpOptions).pipe(
tap(_ => this.log(`updated users id=${user.id}`)),
catchError(this.handleError<any>('updateUser'))
);
}
addUser(user: User): Observable<User> {
return this.http.post<User>(this.usersUrl, user, this.httpOptions).pipe(
tap((newUser: User) => this.log(`added user w/ id=${newUser.id}`)),
catchError(this.handleError<User>('addUser'))
);
}
And first no working. No communicating with .Net, where is wrong data? I can't find any. Mayby parameters is incorect. But I do not see. Any other function working, I have responde and in debug the server is requested but on first request no. Only in POSTMAN or SWAGGER.
I have in orders on Angular:
getOrder(user: string): Observable<Book[]> {
const url = `${this.orderUrl}/name/${user}`;
return this.http.get<Book[]>(url)
.pipe(
tap(_ => this.log(`fetched order for name=${user}`)),
catchError(this.handleError<Book[]>('getBooks', []))
);
}
Is working to.
When I try to use Postman or Swagger I see responde.
P.S when I coppy address on debug from:
const url = `${this.orderUrl}/name/${user}`;
And try in postman added Book in JSON:
{
"bookID": 4,
"title": "string2",
"author": "strin2g",
"isbn": "stri2ng"
}
I have responde.

By default POST method parameters must all be in the request body (FromBody).
GET method parameters must all be in the request query (FromUri).
To change this behavior, you need to add Parameters Bindings.
.net Parameter Binding docs
Changes
[HttpPost("name/{name}")]
public async Task<ActionResult<Book>> PostOrder(
[FromUri] string name,
[FromBody] Book book)
{
// CODE
}

Ok. I have a answer. I havae a:
const url = `${this.orderUrl}/name/${user}`;
return this.http.post<Book>(this.orderUrl, book, this.httpOptions)
But must be:
const url = `${this.orderUrl}/name/${user}`;
return this.http.post<Book>(url, book, this.httpOptions)
Sory for problem. I didn't notice it.

Related

How to capture ActionResult Api Response in Angular?

I have the below method in my user controller:
[HttpPost]
public async Task<ActionResult<bool>> Create(User user)
{
var userCreated = userService.register(user); // returns true or false
if (userCreated)
{
return Ok();
}
else
{
return BadRequest("Could not create user.");
}
}
This method should then be captured in my angular calling the service:
onSubmit(user: User): void {
this.userService.registerUser(user).subscribe((response) => {
console.warn(response);
});
}
The register URL method:
registerUser(user: User): Observable <boolean> {
const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) };
return this.http.post<boolean>(environment.userUrl, user, httpOptions);
}
Unfortunately, the console writes null. Am I missing out anything? I want to capture whether the status is OK or BadRequest.
In your controller you are missing to return the value of your response:
[HttpPost]
public async Task<ActionResult<bool>> Create(User user)
{
var userCreated = userService.register(user); // returns true or false
if (userCreated)
{
return Ok(userCreated); // <= HERE
}
else
{
return BadRequest("Could not create user.");
}
}
After changing the above, you should be OK.
A small tip is that you don't need to add HttpOptions on every request in Angular.
The HttpClient is doing that for you:
registerUser(user: User): Observable<boolean> {
return this.http.post<boolean>(environment.userUrl, user);
}
PS: Ok() in C# means that you are returning a response with code 200.
On the other hand, a BadRequest() will result a 400 error code and will be caught as error inside subscription. In your case I thing that the code in the back end should be like this:
[HttpPost]
public async Task<ActionResult<bool>> Create(User user)
{
var userCreated = userService.register(user); // returns true or false
return Ok(userCreated);
}

how can I parse data to Json and return to another method using Createdataction?

I have a post method to add a new category and save it to the database. and I want to return CreateAtAction to another getmethod.but as I execute the code the data saves in the database with 200 success.
When I try to use Swagger UI though I get "Can not parse json data" and this post method does not move to another get method.
CategoryController.cs
[HttpPost]
public async Task<IActionResult> AddCategory([FromBody] Category category)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_categoryRepository.Add(category);
await Task.Run(() => _categoryRepository.SaveChanges());
return CreatedAtAction(nameof(GetCategoryById) , new { id = category.Id }, category);
}
[HttpGet("{id}")]
public IActionResult GetCategoryById([FromRoute]long id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//var category = await _context.Category.FirstOrDefaultAsync(i => i.ParentId == id);
var ListCategories = _categoryRepository.GetById(id);
if (ListCategories == null)
{
return NotFound();
}
return Ok(ListCategories);
}

Post request working on postman (status 201) but on angular status 409 (conflict)

I have many to many relationship between Contact entity and Tag entity. When I try to add tag on contact that already exists on some other contact I get status 409 response. On the other hand, in Postman I can add tag without a problem (status 201).
// POST: api/TagContacts
[ResponseType(typeof(TagContact))]
public async Task<IHttpActionResult> PostTagContact(TagContact tagContact)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.TagContacts.Add(tagContact);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = tagContact.ContactID }, tagContact);
}
createTagContact(obj: TagContactDTO): Observable<TagContactDTO>{
return this.http.post<TagContactDTO>(this.URL_TAG_CONTACTS, obj);
}
public createTag(){
if(this.tag === ""){
return;
}
this.api.createTag(new TagDTO(this.tag)).subscribe(
res => {
console.log(res.ID);
console.log(this.getContactId());
this.api.createTagContact(new TagContactDTO(this.getContactId(), res.ID)).subscribe(
res => {
this.getContactTags();
}
)
},
err => {
this.api.searchForTagByName(this.tag).subscribe(
res => {
this.api.createTagContact(new TagContactDTO(this.getContactId(), res.ID)).subscribe(
res => {
this.getContactTags();
}
)
}
)
}
)
}

Can't get the header value from HTTP header in Asp.Net Core 2.0

I have an MVC controller that aims to read the user's info from HTTP header. The header contains user info that returns from a single sign on (SiteMinder). SiteMinder redirects the user to the company login page and returns back to my app along with cookie and HTTP header. The HTTP header contains user's info. My controller is supposed to get those info and display it in the navigation bar.
Here is the controller code:
[HttpGet]
public async Task<IActionResult> GetUser()
{
var person = Request.Headers["HTTP_JHED_UID"].ToString();
if (repository.GetJhedUser(person) != null)
{
var user = await repository.GetUser(person);
var userDto = mapper.Map<User, UserForDisplayDto>(user);
return Ok(userDto);
}
else
{
return null;
}
}
And here is my corresponded repository:
public string GetJhedUser(string value)
{
return context.Users.Where(x => x.JHED_ID == value).ToString();
}
public async Task<User> GetUser(string id, bool includeRelated = true)
{
if(!includeRelated)
return await context.Users.FindAsync(id);
return await context.Users
.SingleOrDefaultAsync(s => s.JHED_ID == id);
}
I receive 500 server error. I am sure that the header has those values.
EDIT: Here is an image of debugging. Even I tried with "Date" the value is nothing. Please note that I refactored my codes to #Nkosi's code below
How to get those user's info (in this case just username) from header so that I can display in my HTML template?
Do not return null from a controller action.
Check that the header actually exists before trying to access it.
Refactor the action to be coded a little more defensively.
[HttpGet]
public async Task<IActionResult> GetUser() {
//was the header provided?
var headerValue = Request.Headers["HTTP_JHED_UID"];
if(headerValue.Any() == false) return BadRequest(); //401
//does the person exist?
var person = headerValue.ToString();
if(repository.GetJhedUser(person) == null) return NotFound(); //404
var user = await repository.GetUser(person);
var userDto = mapper.Map<User, UserForDisplayDto>(user);
return Ok(userDto); //200
}
The repository code for GetJhedUser has a problem as well because calling to string on the linq expression is not doing what you think it does.
I would go further to suggest refactoring GetJhedUser to what it is actually checking
public bool JhedUserExists(string value) {
return context.Users.FirstOrDefault(x => x.JHED_ID == value) != null;
}
this results in the action looking like this
[HttpGet]
public async Task<IActionResult> GetUser() {
//was the header provided?
var headerValue = Request.Headers["HTTP_JHED_UID"];
if(headerValue.Any() == false) return BadRequest(); //401
//does the person exist?
var person = headerValue.ToString();
if(repository.JhedUserExists(person) == false) return NotFound(); //404
var user = await repository.GetUser(person);
var userDto = mapper.Map<User, UserForDisplayDto>(user);
return Ok(userDto); //200
}

Unable to use result of Async DocumentDB operation CreateDocumentAsync

I have created a documentDB on Azure and can successfully create and get documents.
However, whilst documents are successfully created in the DB, I am not able to use the response from CreateDocumentAsync. The code immediately returns to the calling method on the controller. So the debug line is never reached.
Moreover I am setting the id to a guid, but the Document that is returned to the controller has an Id of 1.
Controller
[HttpPost]
[Route("")]
public IHttpActionResult CreateNewApplication(dynamic data)
{
if (data == null)
{
return BadRequest("data was empty");
}
try
{
var doc = _applicationResource.Save(data);
return Ok(doc.Id); //code hits this point and 'returns'
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
Resource
public async Task<Document> Save(dynamic application)
{
Document created;
using (Client)
{
application.id = Guid.NewGuid();
var database = await RetrieveOrCreateDatabaseAsync(Database);
var collection = await RetrieveOrCreateCollectionAsync(database.SelfLink, CollectionName);
//persist the documents in DocumentDB
created = await Client.CreateDocumentAsync(collection.SelfLink, application);
}
Debug.WriteLine("Application saved with ID {0} resourceId {1}", created.Id, created.ResourceId);
return created;
}
Get requests return data as expected:
[HttpGet]
[Route("{id}")]
public IHttpActionResult GetApplication(string id)
{
var application = _applicationResource.GetById(id);
return Ok(application);
}
That's because you're not awaiting an asynchronous method:
This:
var doc = _applicationResource.Save(data);
Needs to be:
var doc = await _applicationResource.Save(data);
Your method should look as follows:
[HttpPost]
[Route("")]
public async Task<IHttpActionResult> CreateNewApplication(dynamic data)
{
if (data == null)
{
return BadRequest("data was empty");
}
try
{
var doc = await _applicationResource.Save(data);
return Ok(doc.Id); //code hits this point and 'returns'
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}

Categories