I have spent a about 2 days setting up my Odata Web API project that was before a simple Asp.net mvc4 project.
But still I am not successful in operating even CRUD Operations.
It says this:
<m:message xml:lang="en-US">
No HTTP resource was found that matches the request URI 'http://localhost:53208/odata/Product'.
</m:message>
<m:innererror>
<m:message>
No action was found on the controller 'Product' that matches the request.
</m:message>
<m:type/>
<m:stacktrace/>
</m:innererror>
It means its reaching the Controller but not finding actions or there is some problem in my routing settings.
I have following in my WebApiConfig:
config.Routes.MapODataRoute("OData","odata",GetEdmModel());
My getEdmModel method:
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Product");
builder.EntitySet<OfferedProduct>("OfferedProduct");
IEdmModel model = builder.GetEdmModel();
return model;
}
My controller is like this:
public class ProductController : EntitySetController<Product,int>
{
private OfferAssistantDbContext db = new OfferAssistantDbContext();
List<Product> Products = new OfferAssistantDbContext().Products.ToList();
// GET api/Product
[Queryable(PageSize = 10)]
public override IQueryable<Product> Get()
{
return Products.AsQueryable();
}
// GET api/Product/5
public Product GetProduct([FromODataUri] int id)
{
return Products[id];
}
/// and so on... but for this time lets work only on GET operation
Now when I write this in my browser:
http://localhost:53208/odata/Product
it says the error I showed above..
Please guide me where is the problem?
I believe that your controller needs to inherit from ODataController:
public class ProductController : ODataController
Related
EDIT: If I create an empty ASP.NET CORE WEB APP MVC, I can make it working. I am having problem when I am using MVC with Angular. There might be a problem with SPA proxy as well.
EDIT 2: I found a report https://github.com/dotnet/aspnetcore/issues/38354
I am still trying but no chance.
I can not access my public methods in controller classes. This is my controller:
[Route("authentication")]
public class AuthenticationController : Controller
{
[HttpGet("example")]
public IActionResult Example()
{
return Ok("This is the Welcome action method...");
}
}
And also I tried this attribute as well:
[Route("[controller]")]
public class AuthenticationController : Controller
when I try to navigate to localhost:PORT/authentication/example I am getting 404. I am not using API. I am trying to build a web application with .net core MVC and angular. So I will be just sending GET or POST requests to controllers.
This is my program.cs file
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
app.Run();
I strongly believe that something is wrong in my program.cs. But I couldn't figure it out.
FIX:
After trying out a few days, I finally found the answer. I had to add my new route into 'proxy' variable in proxy.conf.js file.
const PROXY_CONFIG = [
{
context: [
"/weatherforecast",
"/authentication"
],
target: target,
secure: false,
headers: {
Connection: 'Keep-Alive'
}}
]
you can try this for example, it will work for localhost:PORT/authentication/example
[Route("[controller]/[action]")]
public class AuthenticationController : Controller
{
public IActionResult Example()
{
return Ok("This is the Welcome action method...");
}
}
//or
public class AuthenticationController : Controller
{
[HttpGet("~/Authentication/Example")]
public IActionResult Example()
{
return Ok("This is the Welcome action method...");
}
}
but since you are using a Controller as a base class, not an ApiController for example, everything should be working even if you remove all attribute routing at all.
You need to decorate your controller with method / routing attributes
Try:
[Route("api/[controller]")]
public class AuthenticationController : Controller
{
[HttpGet("example")]
public IActionResult Example()
{
return Ok("This is the Welcome action method...");
}
}
This will create a get endpoint which can be called at api/authentication/example
Returning a 200 status with the text in the body.
The convention is that if Your memers start with an action verb, it can find out automatically, like
public string GetExample()
However you do not want to return raw string, you always want to return an action result, because you want wrapping with explicit HttpStatus response codes, so
public IActionResult<string> GetExample()
Now many of us a bias towards the works by magic because of prefix and like to be more explicit, not only because the attribute notation allows more control, but also for consistency. Because nearly almost always, at least one action method of the controller actually requires that fine grain.
[HttpGet("example")]
public IActionResult<string> Example()
Then often for instance there is an id and you can go
[HttpGet("example/id?")]
public IActionResult<string> Example([FromRoute] string id)
if you want to not have it go through all the places it might be getting your variables from for instance, there are many choices available
I have set up a very simple ASP.NET Core 2.1 Web API project, and have created to following simple controller that fetches entites using EF Core.
The problem is that when trying to access the GetEntities method using Postman, the response is a 404 error. I used an HTTP GET method on the following URL.
https://localhost:44311/api/entities
The response body contains the message <pre>Cannot GET /api/entities</pre>.
Why is Postman receiving a 404 error for this route?
EntitiesController.cs
namespace MyProject.Controllers
{
[Route("api/controller")]
public class EntitiesController : Controller
{
private readonly ApplicationDbContext dbContext;
public EntitiesController(ApplicationDbContext _dbContext)
{
this.dbContext = _dbContext;
}
[HttpGet]
public IActionResult GetEntities()
{
var result = dbContext.Entities.ToListAsync();
return Ok(result);
}
}
}
Why is Postman receiving a 404 error for this route?
The issue was the controller token [controller] was missing from the route template on the controller, causing the route to be hard-coded to api/controller.
That meant that when requesting api/entities it technically did not exist and thus 404 Not Found when requested.
Update the route template on the controller.
[Route("api/[controller]")]
public class EntitiesController : Controller {
private readonly ApplicationDbContext dbContext;
public EntitiesController(ApplicationDbContext _dbContext) {
this.dbContext = _dbContext;
}
//GET api/entities
[HttpGet]
public async Task<IActionResult> GetEntities() {
var result = await dbContext.Entities.ToListAsync();
return Ok(result);
}
}
Reference Routing to controller actions in ASP.NET Core : Token replacement in route templates ([controller], [action], [area])
Your route is "api/controller", not "api/entities". You need to put square brackets around "controller" for the desired effect - "api/[controller]".
Makesure the controller file name and the class name is correct, it should be postfix with word"Controller" eg., UsersController.cs
I have web api with OData controller. Models is
public class UserDto
{
public int UserDtoId {get;set;}
public string Name {get;set;}
}
in controller I have two method
[EnableQuery]
public IQueryable<UserDto> Get();
[EnableQuery]
public SingleResult<UserDto> GetUser([FromODataUri] int key);
OData config is:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<UserDto>("Users").EntityType.HasKey(e=>e.UserDtoId).Name = "User";
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: "odata",
model: builder.GetEdmModel());
when I try invoke odata/Users(123), the odata try to invoke first get not a get with a key and return me all record from table. When I comment out first get method there is none GET method for this URI access at all. Where I make a mistake?
I try to make [ODataRoute] its doesnt change nothing.
In your code, your two functions are Get() and GetUser(int key)
They should both be 'Get'
Also not sure if it matters, but for the Get(int) one, if it still doesnt work, try changing SingleResult<UserDto> to just UserDto
I have a OData web api using ADO.NET Framework in which the controller action is somehow not being reached.
The API correctly receives the HTTP request and parses it to go to the correct action but the action is not reached.
And in return the chrome browser shows the authentication window.
I have been debugging so long but cannot figure out how to solve this.
The controller is (stripped version):
public class DataController : ODataController
{
private readonly DataModel DataAccessModel = new DataModel();
public DataController()
{
.......
}
[HttpGet, EnableQuery]
public IQueryable<Record> GetRecord(ODataQueryOptions<Record> options)
{
try
{
IQueryable<ActivationRequestLog> result;
try
{
result = DataAccessModel.Recordss;
}
catch (Exception ex)
{
......
}
}
}
}
Can you show how the controller has been registered in the WebApiConfig class?
If you're using the ODataConventionModelBuilder, then you have to follow certain naming conventions for controllers of entity sets.
e.g. If I register an Airlines entity set of type Airline
builder.EntitySet<Airline>("Airlines");
....then by default/convention I need to implement
public class AirlinesController : ODataController<Airline>
{
[EnableQuery]
public IQueryable<Airline> Get()
{
DB db = Request.GetContext();
return db.Airlines();
}
}
I'm using OData Attribute Routing for an OData endpoint. Here is an example of what I have:
[ODataRoutePrefix("Profile")]
public class ProfileODataController : ODataController
{
[ODataRoute]
[EnableQuery]
public IHttpActionResult Get()
{
var repo = new Repositories.ProfileRepository();
return Ok(repo.GetProfiles());
}
[ODataRoute("({key})")]
[EnableQuery]
public IHttpActionResult Get([FromODataUri] string key)
{
var repo = new Repositories.ProfileRepository();
var result = repo.GetProfiles().SingleOrDefault(x => x.Id== key);
if (result == null) return NotFound();
return Ok(result);
}
}
Here is my set up:
config.MapODataServiceRoute("odata", "odata", ModelGenerator.GetEdmModel());
Here is my EdmModel Generation:
public static IEdmModel GenerateEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Profile>("Profile").EntityType.HasKey(x => x.Id);
return builder.GetEdmModel();
}
The urls /odata/Profile and /odata/Profile('someid') both work, but when I try to access the $metadata endpoint (/odata/$metadata#Profile), I get the following error:
{"Message":"No HTTP resource was found that matches the request URI 'http://****/odata/$metadata'.","MessageDetail":"No type was found that matches the controller named 'Metadata'."}
Do I need to create a controller/action for serving the metadata? If so, how is that action implemented?
Turns out it had to do with my replacement of the IAssembliesResolver.
I had implemented a custom version to provide only the component assemblies that I had implemented controllers in. However, as the error said, it couldn't find a controller named MetadataController. Turns out, OData implements one: System.Web.OData.MetadataController, which provides for the $metadata keyword.
Since I had implemented my own IAssembliesResolver, the System.Web.OData assembly wasn't being included, and $metadata failed. Once I discovered this, and updated my assembly resolver to explicitly include the OData assembly, it now works as it should.