Can't use Json() in asp.net core web api as it in asp.net core web - asp.net-core

In asp.net core web I create a controller and I can use:
return Json(new {status=true});
but in asp.net core web API I can't do it.
In a controller:
[HttpGet("{id}")]
public JsonResult Get(int id)
{
}
I can not return Json()
How to use it?

Asp.Net Core Web API does provide support for wide varieties of response types, with Json being one among them. You can do that like shown below. Make sure you have all your required dependencies. You can learn about the dependencies from the documentation link I attached in this answer.
[HttpGet]
public IActionResult Get()
{
return Json(model);
}
You can also specify strict response formats using the [Produces] Filter on your controller.
Configuring Custom Formatters
You can also configure your own custom formatters in Asp.Net Web API project by calling the .AddFormatterMappings() from ConfigureServices method inside of your Startup.cs. This allows for a greater control on your content negotiation part and lets you achieve strict restrictions.
Please go through this documentation to understand further.
Using Responses with Status Codes
However, when using Web API, I suggest you use the helper methods that are built in so that your response becomes more expressive as it contains both the response content along with the status code. An example of how to do that is below
[HttpGet]
public ActionResult Get()
{
return Ok(_authors.List());
}
For a full list of helper methods available, you can take a look at the Controller.cs and ControllerBase.cs classes.

Asp.net core web api inherit from controllerBase, which doesn't contain a Json(Object) method. You should initialize a new JsonResult yourself in the action.
[HttpGet("{id}")]
public JsonResult Get(int id)
{
return new JsonResult(new { status = true });
}

Related

Attribute Routing in ASP.NET Core OData 8.0 not working

I have been attempting to follow this post to enable attribute routing in OData 8.0.10:
Attribute Routing in ASP.NET Core OData 8.0 RC
During development of v8 ODataRouteAttribute and ODataRoutePrefixAttribute have been removed and routing is supposed to follow regular ASP.NET Core attribute routing, however I cannot get this to work as described.
I register OData as follows:
// build edm:
model = builder.EntitySet<Stuff.PersonProfile>("personProfiles");
// startup.cs
odataOptions.Count().Filter().Expand().Select().OrderBy().SetMaxTop(3).AddRouteComponents("", model)
// person profiles controller:
[Route("personProfiles")]
public class PersonProfilesController : ODataController
{
[HttpGet("Person")]
IActionResult GetPerson(ODataQueryOptions<Stuff.PersonProfileService.Models.PersonProfile> options)
{
}
}
This creates the endpoint correctly and I can reach it:
APIStuff.Controllers.PersonProfilesController.GetPerson (Stuff.API)
GET personProfiles/Person
However no OData endpoint mapping is created. If I remove the attribute route on the GetPerson method, then it DOES. i.e.: I get OData returned in the payload of the personProfiles endpoint that it creates.
It appears this was possible in the 8.0 preview as described in the following:
Routing in ASP NET Core 8.0 Preview
Where clearly there are examples of using attribute routing on the controller and the method. e.g.:
[ODataRoutePrefix("Customers({id})")]
public class AnyControllerNameHereController : ODataController
{
[ODataRoute("Address")]
public IHttpActionResult GetAddress(int id)
{
//......
}
[ODataRoute("Address/City")]
public IHttpActionResult GetCity(int id)
{
//......
}
}
I can only assume this has been removed or I am missing a very big elephant in the room.
Since 8.0 RC, attribute routing is changed to use [Route] and [HttpGet], etc
From your description, ‘personProfiles’ is an entity set, and “Person” looks like a property defined by the type of “personProfiles”, right?
If that’s the case, based on OData spec, you should query a property from an entity (a single entity). It means you should specify the key/id.
You can put the key in [Route] or in [HttpGet].
// person profiles controller:
[Route("personProfiles")]
public class PersonProfilesController : ODataController
{
[HttpGet("{key}/Person")] // this will generater route as: ‘personProfiles/{key}/Person’. It’s key as segment.
IActionResult GetPerson(ODataQueryOptions<Stuff.PersonProfileService.Models.PersonProfile> options)
{
}
}
// person profiles controller:
[Route("personProfiles({key})")] // this will generater route as: ‘personProfiles({key})/Person’. It’s key in parenthesis.
public class PersonProfilesController : ODataController
{
[HttpGet("Person")]
IActionResult GetPerson(ODataQueryOptions<Stuff.PersonProfileService.Models.PersonProfile> options)
{
}
}
Thanks,
-Sam

Block server-to-server or Postman calls to ASP.NET Core 3.1 API

I have a ASP.NET Core 3.1 API where I have not used CORS. As I understand, CORS is a browser thing. And as my ajax calls from another site on another origin is blocked to the API endpoints (which is great), I can still reach the same endpoints by using Postman or a HttpClient and GetAsync() calls.
My question is of it's possible to also block server-to-server calls (or Postman calls) to my API? Or like CORS, only allow certain origins?
Most of my endpoints are protected by a bearer JWT token, but I have an anonymous endpoint that I would like to let only origins I control (or can configure) to have access to that anonymous API.
I solved it after i bumped in to this post on stackoverflow:
How do you create a custom AuthorizeAttribute in ASP.NET Core?
I simply made a custom Authorize attribute [ApiAuthorize()], that I call this way:
[ApiController]
[ApiAuthorize(new string[] { "https://localhost:44351", "https://mysite.onthe.net" })]
public class MyInternalApiController : ControllerBase
{
...
}
It may also be implemented on the Action instead of the Controller. The implementation was done like this:
public class ApiAuthorizeAttribute : TypeFilterAttribute
{
public ApiAuthorizeAttribute(string[] origins) : base(typeof(ApiAuthorizeFilter))
{
Arguments = new object[] { origins };
}
}
public class ApiAuthorizeFilter : IAuthorizationFilter
{
readonly string[] _origins;
public ApiAuthorizeFilter(string[] origins)
{
_origins = origins;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
if (_origins == null)
return;
string referer = context.HttpContext.Request.Headers["Referer"].ToString();
if (string.IsNullOrWhiteSpace(referer) || !_origins.Any(origin => referer.StartsWith(origin, StringComparison.OrdinalIgnoreCase)))
context.Result = new ForbidResult();
}
}
Things to consider:
The implementation and check of the referer could be exact match instead of StartsWith
The handling could use RegEx or any good alternative to handle subdomains, wildcards etc
The referer could be translated to a Uri objects to get better results and variations
A jQuery ajax call gets a "403 - Forbidden" as expected, but Postman gets a "404 - Not Found". To me that does not matter, but that's something to look into if it matters.
But it covers what I need, so I'm happy with this.

Customaze API Attribute

Good afternoon, I study .NET CORE. How to create a custom attribute for the controller API? I want to allow requests to controllers from certain ip addresses.
In ASP. Net framework I created a custom attribute inheriting from "AuthorizeAttribute" then I just add my attribute to my controller.
I want that controller work from specific Ip address
Create attribute inherited from IAuthorizationFilter to have similar behavior to previous ASP.NET framework.
public class IpAuthorizationAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (/*ip not allowed*/)
{
//return 401 Unauthorized
context.Result = new UnauthorizedResult();
}
}
}
However, Microsoft recommends policy based authorization for ASP.NET Core.

How create a middleware with api endpoints in .NET Core

I have created the web application with the web api. The application contains some Controllers for example TodoController:
namespace TodoApi.Controllers
{
[Route("api/[controller]")]
public class TodoController : Controller
{
private readonly TodoContext _context;
public TodoController(TodoContext context)
{
_context = context;
}
[HttpGet]
public IEnumerable<TodoItem> GetAll()
{
return _context.TodoItems.ToList();
}
}
}
If I create the GET request - /api/todo - I get the list of Todos from database.
I have a list of controllers and api endpoints like above.
I would like distribute this api to another application ideally like middleware - my idea is register in Startup.cs like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddTodoApi();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseTodoApi();
}
This will be awesome use case for my api but I don't know how this controllers api endpoints rewrite like middleware and return same JSON data same approache like using classic Controllers.
How can I write the middleware in .NET Core for creating API endpoints?
Instead of the separate middleware, you may configure the MVC middleware to discovery controllers from another assembly:
// using System.Reflection;
public void ConfigureServices(IServiceCollection services)
{
...
services
.AddMvc()
.AddApplicationPart(typeof(TodoController).GetTypeInfo().Assembly);
Controllers are part of MVC middleware, they are not a separate part of request pipeline (but this is what middlewares are). When you register the custom middleware, it by default invokes on each request and you have HttpContext context as an input parameter to work with/edit
Request/Response data. But ASP.NET Core provides Map* extensions that are used as a convention for branching the pipeline.
Map branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed.
Example:
private static void HandleMapTodo(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("/api/todo was handled");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/api/todo", HandleMapTodo);
}
Note, that as middleware knows nothing about MVC middleware, you have only access to "raw" request and do not have features like model binding or MVC action filters.
Because it looks like the perfect microservices approach (similar than what my team is doing right now) I'd create a client assembly that can consume your API, the one that contains your TodoController, if you define a contract, and interface, for that API you can register it in your other assembly as it was a midleware and also you could mock that behaviour in your unit tests.
So, as I said, you could inject your client in ConfigureServices method, you can create:
public static IServiceCollection AddTodoRestClient(this IServiceCollection services)
{
services.AddSingleton<ITodoRestClient, TodoRestClient>();
return services;
}
Also consider that you will need to provide the enpoint so, it might looks like:
public static IServiceCollection AddConfiguredTodoClient(this IServiceCollection services, string todoEndpoint)
{
AddTodoClient(services);
ITodoRestClient todoRestClient = services.BuildServiceProvider().GetService<ITodoRestClient>();
// Imagine you have a configure method...
todoRestClient.Configure(services, todoEndpoint);
return services;
}
You can create those methods in a TodoRestClientInjector class and use them in Configure method on your startup.
I hope it helps
--- MORE DETAILS TO ANSWER COMMENTS ---
For me TodoClient is a Rest client library that implements calls to the ToDo API, (I've edited previous code to be TodoRestClient) methos like, i.e., CreateTodoItem(TodoDto todoItem) which implementation would call to the TodoController.Post([FromBody] item) or GetTodos() which wuold call TodoController.Get() and so on and so forth....
Regarding the enpoints... This approach implies to have (at least) two different applications (.NET Core apps), on the one hand the ASP NET Core app that has your TodoController and on the other hand a console application or another ASP NET Core API on which startup class you'll do the inyection adn the Rest client (the Todo Rest client) configuration ...
In a microservices approach using docker, in a dev environment, you'll use docker-compose-yml, but in a traditional approach you'll use concrete ports to define the endpoints...
So, imagine that you have in the second service a controller that need to use TodoController, to achieve so I'll use the above aproach and the "SecondController" would look like:
public class SecondController : Controller
{
private readonly SecondContext _context;
private readonly TodoRestClient _todoRestClient;
public TodoController(SecondContext context, ITodoRestClient todoRestClient)
{
_context = context;
_todoRestClient= todoRestClient;
}
// Whatever logic in this second controller... but the usage would be like:
_todoRestClient.GetTodos()
}
Just few final hints: it's key to minimize calls between services because it increases latency, and more and more if this happens on cascade. Also consider Docker usage, looks challenging but it is quite easy to start and, indeed, is thought to be used in scenarios that the one you presented and solutions like mine.
Again, I hope it helps.
Juan

How to handle PROPFIND HTTP Verb requests (or other) in ASP.NET Core?

I am looking for implementation options how to handle requests with more exotic HTTP verbs like PROPFIND or MKCOL with ASP.NET Core or ASP.NET Core MVC.
In ASP.NET Core MVC you can decorate your action methods with
[HttpGet]
[HttpPut]
[HttpPost]
[HttpDelete]
[HttpHead]
[HttpOptions]
[HttpPatch]
For a REST API or web applications these HTTP verbs are sufficient. For WebDav for example PROPFIND or MKCOL verbs have to be handled somehow, too.
Is there a possibility to extend ASP.NET Core MVC to support more HTTP verbs than the ones listed above ?
Or do you think that writing an own middleware component is the better approach to add WebDav capabilities to a ASP.NET Core app ?
I have looked into the ASP.NET Core Source Repositories to get some ideas. But I am stuck in the moment.
The solution is easier than I thought. You can invoke Controller Actions by a HTTP verb like this
public class WebDavController : Controller
{
[HttpGet]
[Route("/dav/{fileName}")]
public IActionResult Get(string fileName)
{
// a classic Get method
....
}
[Route("/dav/{fileName}")]
public IActionResult Propfind(string fileName)
{
// this is invoked if http verb is PROPFIND
// (framework searches for corresponding action name)
....
}
[AcceptVerbs("LOCK")]
[Route("/dav/{fileName}")]
public IActionResult MyLockAction(string fileName)
{
// this is invoked if http verb is LOCK
// (framework searches annotated action method)
....
}
}