I am trying to implement a simple Breeze controller in Asp.Net MVC4, but can't seem to access it. Is it possibly conflicting with .Net's standard Web.Api ?
If my url is http://localhost:49479/api/values then I get a good return value from Web Api.
However if my url is http://localhost:49479/breeze/Breeze I get "Http 404" error "Resource not found".
If my url is http://localhost:49479/breeze/Breeze/5 I get error No HTTP resource was found that matches the request URI 'http://localhost:49479/breeze/Breeze/5'.
Your advice is greatly appreciate.
Here's what I have in ..Controllers/BreezeController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Breeze.ContextProvider;
using Breeze.WebApi2;
using Newtonsoft.Json;
namespace RageSys.Controllers
{
[BreezeController]
public class BreeezeController : ApiController
{
// GET api/values
public string Get(int id)
{
return "value";
}
public IEnumerable<string> GetMtm(int id)
{
return new string[] { "value1", "value2" };
}
}
}
and in BreezeWebApiConfig.cs :
using System.Web.Http;
[assembly: WebActivator.PreApplicationStartMethod(
typeof(RageSys.App_Start.BreezeWebApiConfig), "RegisterBreezePreStart")]
namespace RageSys.App_Start {
///<summary>
/// Inserts the Breeze Web API controller route at the front of all Web API routes
///</summary>
public static class BreezeWebApiConfig {
public static void RegisterBreezePreStart() {
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "breeze/{controller}/{action}"
);
}
}
}
The result you are getting from your api/values request is not coming from the listed controller. You must have the default ValuesController and WebApiConfig (which defines a route that takes a parameter) still in your project.
You do not have a route for http://localhost:49479/breeze/Breeze/5. The third segment (currently 5) needs to be the name of an Action method. For you, that means GetMtm. You do not have a route that takes any parameters, so you'll get nothing from: http://localhost:49479/breeze/Breeze/GetMtm/5 unless you define such a route. You probably don't want to do this though, because Breeze coupled with Entity Framework will make life very easy. You should implement the simplest possible Breeze / Entity Framework application and see how it works from there.
If you are using parameters and using Breeze, then ensure you use the .withParameters({ ParameterName: "Fred"}) or .withParameters({ id: id-value}), for example, in your Breeze query and ensure the parameter name in your function to be called (GetMtm in your case) at the server matches the parameter name you are using at the client.
Related
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
I am trying to use the BackgroundService is an asp.net core 2.2 project using the Razor page project template, not MVC. This little sample app took me about 1 minute to write so it couldn't be much simpler. Looking at the debugger I know the background service is starting and chugging along just fine. But when I attempt to navigate to a page (path 'Banana') that requires this service as a dependency, I get InvalidOperationException: Unable to resolve service for type 'WebApplication23.DumbService' while attempting to activate 'WebApplication23.Pages.BananaModel'. Why can't I access this service from my page model? The code is at https://github.com/jmagaram/SimpleBackgroundService
I have the following service:
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
namespace WebApplication23
{
public class DumbService : BackgroundService
{
public DumbService()
{
}
public void QueueWork()
{
}
protected async override Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested) {
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
}
}
And this is where I register it:
services.AddHostedService<DumbService>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Here is a page model that uses it:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace WebApplication23.Pages
{
public class BananaModel : PageModel
{
private readonly DumbService _service;
public BananaModel(DumbService service)
{
_service = service;
}
public void OnGet()
{
}
}
}
Registering a background service doesn't actually add it to the service collection, mostly because there's no need to. The whole point of a background service is that your app doesn't really need to know about it. It's not clear why you think you need this service injected, but almost certainly you'd be better served by factoring out whatever logic you need in your Razor Page into a separate class that both the service and your Razor page can utilize.
UPDATE
See the documentation on IHostedService where an example of a queue background service is given. You'll notice that the actual hosted service is injected with the task queue. Your app then would also inject just the task queue itself to schedule tasks.
Hopefully not a dumb question- I am rewriting an app from .net core mvc to .net core Razor. In MVC I use viewbags to create and display confirmation of actions being successful or display error message if not. Viewbags don't seem to be used or available in the same way for Razor pages in .net core 2.1.
How do you achieve the above in Razor pages? Any code snippets as example would be helpful. Thanks
We can use a Post-Redirect-Get pattern to display a message after an action.
Here is an example that uses TempData to store a message during a POST and then redirects to a GET. Using TempData to store the message is particularly appropriate for redirection, because the data only exists until something reads it.
SomePage.cshtml
#page
#model SomePageModel
#if(TempData[SomePageModel.MessageKey] is string message)
{
<p>#message</p>
}
<form method="POST">
<button type="submit">POST!</button>
</form>
SomePage.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace temp.Pages
{
public class SomePageModel : PageModel
{
public const string MessageKey = nameof(MessageKey);
public void OnGet() { }
public IActionResult OnPost() {
TempData[MessageKey] = "POST Success!";
return RedirectToAction(Request.Path); // redirect to the GET
}
}
}
This pattern also works for HTTP methods such as PUT and DELETE. Simply substitute any other HTTP verb; for instance, we can do a Put-Redirect-Get.
This OData function does not deserialize the model parameter from the body. It deserializes as null as seen from response. Is there support for FromBody parameters in OData V4?
ConfigV1.cs
builder.Function("CreateTestModel").Returns<TestModel>();
var edmModel = builder.GetEdmModel()
config.MapODataServiceRoute("ODataRouteV1", "v1", edmModel);
TestController.cs
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Query;
using System.Web.OData.Routing;
public class TestController : ODataController
[HttpPost]
[ODataRoute("CreateTestModel")]
public TestModel CreateTestModel([FromBody]TestModel model)
{
return model;
}
}
TestModel.cs
public class TestModel
{
public string Value { get; set; }
}
Request
POST /v1/CreateTestModel HTTP/1.1
Host: localhost:8090
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 4810cdc0-d92b-b7b5-4328-8b87e0222854
{
"Value": "test"
}
Response
{
"#odata.context":"http://localhost:8090/V1/$metadata#Edm.Null","#odata.null":true
}
OData Functions should be called with an HTTP GET and shouldn't affect the server. Your method here CreateTestModel sounds like it will affect the server so I would say that it is probably more suited to an OData Action. This may seem like it isn't relevant but I think that it will actually fix your issue as well because Actions are setup to have parameters in the body whereas Functions typically get parameters from the URL
In V4 we are using ODataActionParameter in the controller method, you can refer to this page to get detail information, and there are more V4 features.
http://odata.github.io/WebApi/#04-07-action-parameter-support
I'm in the process of converting an ASP.NET MVC3 (LinqToSQL, EntityFramework) project to MVC4. I've created a fresh MVC4 project in VS2012, added packages, copied my Views, Controllers, etc.
Most things seem to work fine except when I try to access a controller that makes use of a Respository, as follows:
public class CustomerController : Controller
{
private ICustomerRepository _cr;
public CustomerController()
{
this._cr = new CustomerRepository(TTDataProvider.DB);
}
public CustomerController(ICustomerRepository customerRepository)
{
this._cr = customerRepository;
}
if I'm in VS2012 and debugging, what I'll get is an exception: "Activation error occured while trying to get instance of type CustomerController, key """. The exception is of type Microsoft.Practices.ServiceLocation.Activation and the Inner Exception is: "StructureMap Exception Code: 202\nNo Default Instance defined for PluginFamily TTLW.Models.TTLWDataContext, TTLW, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}.
My IoC code is:
using StructureMap;
using FluentSecurity;
using System.Diagnostics;
namespace TTLW {
public static class IoC {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.AddAllTypesOf<IPolicyViolationHandler>();
});
});
return ObjectFactory.Container;
}
}
}
And here's StructureMapMVC.cs
using System.Web.Http;
using System.Web.Mvc;
using StructureMap;
using TTLW.DependencyResolution;
[assembly: WebActivator.PreApplicationStartMethod(typeof(TTLW.App_Start.StructuremapMvc), "Start")]
namespace TTLW.App_Start {
public static class StructuremapMvc {
public static void Start() {
IContainer container = IoC.Initialize();
DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = DependencyResolver.Current.ToServiceResolver();
}
}
}
As I say, this was all working without problems in my MVC3 application (although I was of course using the MVC3 version of StructureMap).
Once I hit the exception, if I just choose to continue then everything works (i.e. the controller functions); this is confirmed by choosing "Start Without Debugging" instead of "Debug". When I do that there is no exception thrown and things work as designed.
I've searched and come across posts from Phil Haack, Brett Allred and others (in fact I've already incorporated Allred's code in the last line of StructureMapMVC) but haven't found a solution. I can't consider the project converted as long as this exception is staring me in the face.
I've included all the code and messages I think are reasonable and would appreciate any insights. If you need to see more just let me know.
Thanks in advance.