Unauthorized Message,Status 200 OK - c#

I am doing the backend according to the given architecture given by the company I recently started working.
I am new to C# and now I'm trying to do some post/get/put methods for some api-s.
There is a problem which I couldn't solve it.
Postman says:
{
"code": 1,
"message": "Unauthorize"
}
But the status code is 200 OK.
UserController.cs
[Route("v1/users")]
[Produces("application/json")]
public class UserController : BaseController
{
/// <summary>
/// Get list of users (Authorize)
/// </summary>
/// <returns>
/// </returns>
[ProducesResponseType(typeof(BaseResponseModel<List<UserResource>>), 200)]
[HttpGet]
public async Task<IActionResult> Get()
{
var user = await _userService.GetUserResourcesAsync();
return Success(user);
}
}
This doesn't make any sense, or am I so dumb to realise the problem?
I have a login method and I can login, I get the success code, then I do this:
enter image description here
Header
IProductService.cs
public interface IProductService
{
Task<ProductDto> GetAsync(int id);
}
ProductService.cs
public async Task<ProductDto> GetAsync(int id)
{
var product = await _context.Product.SingleOrDefaultAsync(p => p.Id == id);
return _mapper.Map<ProductDto>(product);
}
ProductDto.cs
public class ProductDto
{
public int Id { get; set; }
public CategoryDto CategoryId { get; set; }
public string Title { get; set; }
public bool AllowEdit { get; set; }
public string ItemCode { get; set; }
public string CustomerCode { get; set; }
}
Product.cs
[Table("Products")]
public class Product : DomainModel<int>
{
[Required]
public int ProductCategoryId { get; set; }
[ForeignKey("ProductCategoryId")]
public virtual ProductCategory ProductCategory { get; set; }
[Required, StringLength(256)]
public string Title { get; set; }
[Required, DefaultValue(false)]
public bool AllowEdit { get; set; }
[StringLength(50)]
public string ItemCode { get; set; }
[StringLength(50)]
public string CustomerCode { get; set; }
}

Using the ProducesResponseTypeAttribute, the attributed API actually defines what should be response code for specified types. See the definition
of at ProducesResponseTypeAttribute.
How it works
Take following example which shows that the API throws the 404 error if the object is null:
public IActionResult GetById(string id)
{
var post = <<Your logic here>>;
if (post == null)
{
return NotFound();
}
return Json(post);
}
Now the same method can be changed to following, which would return 404 by using the ProducesResponseType instead of the code is being written in your API logic.
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public IActionResult GetPostById(string id)
{
var post = <<Your logic here>>;
return Json(post);
}
In cases, it might be good to also define a more explicit response type for successful calls. To do so, add a ProducesResponseTypeAttribute for status code with type. ( return type as parameter, which makes the Type property of Produces redundant).
This is valuable, if you want to return different things from one and the same method, for example, the following returns two different types depending on the returned status code:
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(Model), (int)HttpStatusCode.OK)]
public IActionResult GetById(string id)
What is your problem
Now if you see your code which defines this attribute as [ProducesResponseType(typeof(BaseResponseModel<List<UserResource>>), 200)]. And the code to fetch user :
var user = await _userService.GetUserResourcesAsync();
returns BaseResponseModel<T>. The BaseResponseModel should contain the Code and Message property. So here, the response returned by API is type of BaseResponseModel<T>, so API would return 200 HTTP Status as defined by attribute.
How to Fix
Either you return a different object in case of Unauthorize exception and attach the ProducesResponseType specific to that type OR handle the unathorized logic based at Authorize attribute.

Related

Get json data from POST method in asp.net mvc

I got an error while getting json data from POST method, am I doing something wrong
C# Code:
public IActionResult signupapi(UserSignUp user)
{
var model = new Models.SignUpModelAPI(HttpContext);
if (user == null)
{
return Content(model.ResponseJsonText(false, string.Format(model.Language("empty"),
HttpContext.Request.Method, HttpContext.Request.Path.Value), Class.CodeResponse.ERROR), new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
if (!model.isAllowMethod("POST"))
{
return Content(model.ResponseJsonText(false,string.Format(model.Language("notallowmethod"),
HttpContext.Request.Method,HttpContext.Request.Path.Value),Class.CodeResponse.ERROR),new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
return Content(JsonConvert.SerializeObject(user));
}
public class UserSignUp
{
public string fullname { get; set; }
public string username { get; set; }
public string email { get; set; }
public string password { get; set; }
}
And this is the result when i try on reqbin every value i get is null
You need to add FromBody attribute to get your data for the POST operation:
public IActionResult signupapi([FromBody]UserSignUp user)
You can read more on parameter binding on MSDN docs.

How to correctly pass a string id to API controller in Xamarin.Forms

I'm writing a mobile app using Xamarin Forms where I am going to consume an REST API.
At the moment, I have a user model
{
public string UserId { get; set; }
public string UserDisplayName { get; set; }
public int UserRoleId { get; set; }
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserEmail { get; set; }
public string UserPostcode { get; set; }
public DateTime UserCreatedAt { get; set; }
public DateTime UserModifiedAt { get; set; }
public bool UserDeletedAt { get; set; }
}
And I have defined a GetUser method on my controller
// GET: api/Users/5
[HttpGet("{id}")]
public async Task<ActionResult<User>> GetUser(string id)
{
var user = await _context.User.FindAsync(id);
if (user == null)
{
return NotFound();
}
return user;
}
If I test the API using Postman and parse the string id without quotes(edit) on the route, it works fine. E.g. https://localhost:5051/api/Users/Example. However, if I parse the id within qutoes(edit) it doesn't work: https://localhost:5051/api/Users/"Example"
My problem is, on my mobile client, when it calls the web service that calls the API, it needs to parse a string, which goes with the quotes(edit)- matching the second example.
Does any of you know a solution or a workaround for this?
Thanks in advance
EDIT:
My service method is as follows
public static async Task<IEnumerable<User>> GetUserById(string id)
{
var json = await client.GetStringAsync($"api/users/{id}");
var users = JsonConvert.DeserializeObject<IEnumerable<User>>(json);
return users;
}
And my service call is
var users = await UserService.GetUserById("Example");
EDIT2: Fixed
Service method changed to
public static async Task<User> GetUserById(string id)
{
var json = await client.GetStringAsync($"api/users/{id}");
var users = JsonConvert.DeserializeObject<User>(json);
return users;
}
It turns out the issue was caused by the IEnumerable type on the task definition, which makes sense since I was trying to retrieve a single instance.
Service method changed to
public static async Task<User> GetUserById(string id)
{
var json = await client.GetStringAsync($"api/users/{id}");
var users = JsonConvert.DeserializeObject<User>(json);
return users;
}

What should I put to return one to many list in WebAPI?

I tried to return a object class, however the attempt is failed.
public class tbl_Product
{
public tbl_Product()
{
tbl_ProductDescription = new HashSet<tbl_ProductDescription>();
tbl_ProductPricing = new HashSet<tbl_ProductPricing>();
}
public Guid Id { get; set; }
public string ProductCode { get; set; }
public string ProductName { get; set; }
public Decimal Price { get; set; }
[InverseProperty("Product")]
public virtual ICollection<tbl_ProductPricing> tbl_ProductPricing { get; set; }
}
Below is my WebAPI function during return:
[HttpGet]
public Task<ActionResult<ICollection<tbl_Product>>> GetProductList()
{
var result = _context.tbl_Product
.Include(a => a.tbl_ProductPricing).ToList();
return result;
}
However, I got this error:
Cannot implicitly convert type 'System.Collections.Generic.List<Model.tbl_Product>' to 'System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.ActionResult<System.Collections.Generic.ICollection<Model.tbl_Product>>>'
May I know what's the return type should I put?
[HttpGet]
public async Task<ActionResult<ICollection<tbl_Product>>> GetProductList()
{
return Ok(await _context.tbl_Product.Include(a => a.tbl_ProductPricing).ToListAsync());
}
The returned instance must match the type specified in the method signature. In your case you are specifying that the return type will be Task<ActionResult<ICollection<tbl_Product>>> so it must 1) return a Task and 2) the task must resolve an instance of ActionResult<ICollection<tbl_Product>> and 3) that ActionResult must have the content that implements ICollection<tbl_Product>.
I am assuming you are using .net core and referring to ActionResult<T>

WebApi different DTO for Get and Post

Is it ok to have different DTO's for GET and POST actions ?
The reason for this is there is usually a vast difference between these two data models.
For example:
My POST would look like this:
/// <summary>
/// Add new user
/// </summary>
/// <param name="item">User data</param>
/// <returns>Newly added user id</returns>
[HttpPost]
public IHttpActionResult Post([FromBody] UserDto item)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var model = _mapper.Map<User>(item);
int itemid = _usersRepository.Insert(model);
return Ok(itemid);
}
public class UserDto
{
private string _password;
[Required]
[StringLength(100, ErrorMessage = "Name {0} must consist of at least {2} letters.", MinimumLength = 6)]
public string Name { get; set; }
[Required]
public string ExternalName { get; set; }
[Required]
public bool Active { get; set; }
[Required]
public string Password
{
get { return _password; }
set { _password = value.Hash(); }
}
}
and my GET would look like this:
/// <summary>
/// Get all users
/// </summary>
/// <returns>Users list</returns>
[HttpGet]
[ResponseType(typeof(List<UserInfoDto>))]
public IHttpActionResult Get()
{
IList<UserInfoDto> values = _usersRepository.SelectAll();
if (values == null || !values.Any())
return Ok();
return Json(new { collection = values });
}
public class UserInfoDto
{
public int Id { get; set; }
public string Name { get; set; }
public string ExternalName { get; set; }
public bool Active { get; set; }
}
The reason I'd do this is that I don't need Id when POSTing a resource but Password is necessary. It is reversed when using GET.
Is this the correct approach when using WebApi (Creating different Dtos for responses and requests)? Or is there some other way to do this ?
Is it ok to have different DTO's for GET and POST actions ?
There is nothing wrong with having different dto's for different actions.
If the api is being used by 3rd parties you would want to make sure that it is well documented.
Is this the correct approach when using WebApi?
Whether this is correct approach or not is a matter of opinion. Expose or accept the necessary information for the system to perform as intended.
Each action could use its own unique dto. Doesn't mean that it should. You want to make sure you are not leaking more information than is necessary.

c# WebApi OData complex type is always null in post ODataRoute

My problem is that "siteSetup" is always null for the following odata action:
[HttpPost]
[ODataRoute("Setup")]
public IHttpActionResult Setup(SiteSetup siteSetup)
{
return BadRequest("Not yet working");
}
This is my complex type
public class SiteSetup
{
public SiteSetup()
{
}
public string Username
{
get;
set;
}
public string Password
{
get;
set;
}
public string CompanyName
{
get;
set;
}
}
And this is the fiddler for a request.
Action with complextype as parameter is support in OData/WebApi V4, you may use ODataActionParameters in your controller method, you can see this page for instruction, http://odata.github.io/WebApi/#04-07-action-parameter-support

Categories

Resources