Web Api and MVC controller - same repository, different output - asp.net-mvc-4

Never saw this before. I use both web api and mvc controllers in my app.
I use Structuremap MVC4 dependency injection for both controllers, which works fine.
Using the same repository, when I fetch a procuct from the MVC controller, the result is NULL, but calling for the same product from the Web Api controller, the result is the correct product.
Both hit the same method in the repository, using the same DbContext.
This is the MVC controller action:
public ActionResult ShowProduct(int id)
{
var product = _repo.GetProduct(id);//product is null
return View();
}
This is the Web Api method:
public Product Get(int id)
{
var product = _repo.GetProduct(id);//Returns correct product
return product;
}
This is the repository method used by both controllers:
public Product GetProduct(int id)
{
using (var db = new ProductContext())
{
var product = db.ProductDb.Include(a => a.Orders).FirstOrDefault(c => c.Id == id);
return product; //Call from MVC controller returns NULL
}
}
Any ideas why this happens?

Uhm, I'm almost afraid to tell what the reason for this is...
The two controllers exist in each of their own web projects, and the project with the MVC controller was missing the connectionstring in web.config... DUH...
Think I need some sleep.....

Related

How do I access the shopping cart directly from a controller action?

One of the most popular books on ASP.NET Core is "Pro ASP.NET Core 3" by Adam Freeman.
In chapters 7-11, he builds an example application, SportsStore.
Note the cart information in the upper right corner:
This shows up in the layout via the following line:
<vc:navigation-menu />
See Views/Shared/_Layout.cshtml line 22.
The implementation of the view is at:
Views/Shared/Components/CartSummary/Default.cshtml
As well as the C# code at:
Components/CartSummaryViewComponent.cs
I know that the persistence of the cart data is setup via the following line in Startup.cs:
services.AddScoped<Cart>(obj => SessionCart.GetCart(obj));
See Models/SessionCart.cs for details on SessionCart.
Now for the question.
I've added the following method to HomeController:
[HttpGet]
public ContentResult CartSize()
{
return new ContentResult()
{
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
Content = "cart size here"
};
}
It's a very simple action method which is intended to simply return the number of items in the cart.
Given the how the cart is implemented in the example project, what's a good way to get the number of items in the cart in the CartSize method?
Thanks!
Inject the Cart service into your controller and use in your action method
private Cart cart;
public MyController(Cart cartService) {
cart = cartService;
}
[HttpGet]
public ContentResult CartSize()
{
return new ContentResult()
{
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
Content = cart.Lines.Count().ToString()
};
}

How to dynamically resolve controller with endpoint routing?

Upgrading to asp.net core 2.2 in my hobby project there is a new routing system I want to migrate to. Previously I implemented a custom IRouter to be able to set the controller for the request dynamically. The incoming request path can be anything. I match the request against a database table containing slugs and it looks up the a matching data container class type for the resolved slug. After that I resolve a controller type that can handle the request and set the RouteData values to the current HttpContext and passing it along to the default implementation for IRouter and everything works ok.
Custom implementaion of IRouter:
public async Task RouteAsync(RouteContext context)
{
var requestPath = context.HttpContext.Request.Path.Value;
var page = _pIndex.GetPage(requestPath);
if (page != null)
{
var controllerType = _controllerResolver.GetController(page.PageType);
if (controllerType != null)
{
var oldRouteData = context.RouteData;
var newRouteData = new RouteData(oldRouteData);
newRouteData.Values["pageType"] = page.PageType;
newRouteData.Values["controller"] = controllerType.Name.Replace("Controller", "");
newRouteData.Values["action"] = "Index";
context.RouteData = newRouteData;
await _defaultRouter.RouteAsync(context);
}
}
}
A controller to handle a specific page type.
public class SomePageController : PageController<PageData>
{
public ActionResult Index(PageData currentPage)
{
return View("Index", currentPage);
}
}
However I got stuck when I'm trying to figure out how I can solve it using the new system. I'm not sure where I'm suppose to extend it for this behavior. I don't want to turn off the endpoint routing feature because I see an opportunity to learn something. I would aso appreciate a code sample if possible.
In ASP.NET 3.0 there is an new dynamic controller routing system. You can implement DynamicRouteValueTransformer.
Documentation is on the way, look at the github issue

Where To Place Common Variables in ASP.NET Core

I'm starting a new ASP.NET project after a few years developing in MVC4, and I have a question regarding architecture.
At the top corner of each page, I will display details of the current logged in user.
In MVC4 I achieved something like this by creating a BaseController, which created an EF data connection, and set up some common variables that would be used on every page - CurrentUser being one of them.
Now that I'm using Core, this approach doesn't seem to work, and certainly isnt mockable.
What would be the correct way to achieve something like this via ASP.NET Core?
I need the same variables on every view, and certainly dont want to have to write the code in each controller action!
You can use View Components feature in asp.net core to implement that functionality.
//In your ConfigureServices method , add your services that will be injected whenever view component is instantiated
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<IUserRespository, UserRepository>();
}
//Now Create a view component
public class LoggedInUser : ViewComponent
{
private IUserRespository userRepository;
//Services can be injected using asp.net core DI container
public LoggedInUser(IUserRepository userRepository,SomeOtherService service)
{
//assign services to local variable for use later
this.userRepository = userRepository;
}
//This method can take any number of parameters and returns view
public async Task<IViewComponentResult> InvokeAsync(int param1,string param2,etc )
{
//get the logged in user data here using available services
var loggedInUserData = GetSomeData(context);
return View(loggedInUserData );
}
}
Create view file # View/Shared/Components/LoggedInUser/Default.cshtml.View can be strongly typed.
#model LoggedInUserModel
<div>
<!-- html here to render model -->
</div>
Now, since you use to display this data on every page , you need to apply _Layout.chstml to all your pages . In the _Layout.chstml , you can render view component defined above with any additional parameter you would like to pass as anonymous type.
#await Component.InvokeAsync("LoggedInUser", new { param1=value,param2=value,etc })
Testing the View Component:
var mockRepository = Mock of ICityRepository;
var viewComponent= new LoggedInUser(mockRepository);
ViewViewComponentResult result
= viewComponent.Invoke() as ViewViewComponentResult; //using Invoke here instead of InvokeAsnyc for simplicity
//Add your assertions now on result
Note :
It is also possible to decorate a controller with [ViewComponent(Name = "ComponentName")] attribute and define public IViewComponentResult Invoke()
or public IViewComponentResult InvokeAsync() to turn them in to hybrid controller - view component.

Json Helper Class in Razor Pages Project

I created a simple project and I can't seem to access the Json Helper class that I see through a bunch of sample projects. For example, I'm trying to use the Telerik dropdown sample and in the code below, I get the error:
The name Json does not exist in the current context.
(same thing goes for JsonRequestBehavior) What am I missing? I've done a search in nuget for System.Web.Helpers, but I can't add the reference because the project is targeted for ASP.NET Core 2.0 while the assembly was restored using .NET 4.6.1. What is my alternative?
public JsonResult RemoteDataSource_GetProducts(string text)
{
var northwind = new SampleEntities();
var products = northwind.Products.Select(product => new ProductViewModel
{
ProductID = product.ProductID,
ProductName = product.ProductName,
UnitPrice = product.UnitPrice ?? 0,
UnitsInStock = product.UnitsInStock ?? 0,
UnitsOnOrder = product.UnitsOnOrder ?? 0,
Discontinued = product.Discontinued
});
if (!string.IsNullOrEmpty(text))
{
products = products.Where(p => p.ProductName.Contains(text));
}
return Json(products, JsonRequestBehavior.AllowGet);
}
Json(JsonResult) is a class and JsonRequestBehavior is an enum that lives within System.Web.Mvc in ASP.NET Framework. In ASP.NET Core, Json(JsonResult) lives within Microsoft.AspNetCore.Mvc.
You should be just fine with,
return Json(products);

WebApi and MVC 4: GetById and services in separate project

I'm working with webapi, MVC 4 project. (using repository pattern and Unit of Work)
I have two questions
1) The GetById of WebApi should return the entity or HttpResponseMessage?
If it's HttpResponseMessage, then Should it be...
[System.Web.Http.HttpGet]
public HttpResponseMessage Get(int id)
{
var car = Uow.Cars.GetById(id);
return car == null ? Request.CreateResponse(HttpStatusCode.OK, car) : Request.CreateResponse(HttpStatusCode.NotFound,);
}
or
[System.Web.Http.HttpGet]
public HttpResponseMessage Get(int id)
{
var car= Uow.Cars.GetById(id);
if (car!= null) {
return car;
}
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
I'd like to follow RESTfull responses.
2) Is it logical to separate webapi services from the UI? I mean in one webapi project, the controllers with base ApiController and CRUD http opearations, so they can be called from anywhere/any devices directly, and then another webapi/MVC4 project which will call the services of the webapi project?
I'm asking this because having in the same controller the service and the handling that return a View for example sounds like coupling the service to the client which will be consuming it.
For example:
From this (in the same webapi controller):
[System.Web.Http.HttpGet]
public HttpResponseMessage Get(int id)
{
var car = Uow.Cars.GetById(id);
return car!= null ? Request.CreateResponse(HttpStatusCode.OK, car) : Request.CreateResponse(HttpStatusCode.NotFound,);
}
public ViewResult Details(long id)
{
return View(Get(id));
}
Go to this:
public ViewResult Details(long id)
{
return View(webapiService.Cars.Get(id));
}
Having the implementation of the Get in the service.
You could use HttpResponseMessage or the entity Car as the return type. If you use HttpResponseMessage you would get more control on customizing some of the HTTP properties when you create the response.
When the action creates a resource then using the HttpResponseMessage as the return type provide you much flexible option to set the status code (201) and the location where the created resource can be accessed. See this post for more info.
REST not care about which way you use all it cares is when the caller asks for a resource the server should return the resource in a format that the caller can accept it with proper status code (200 if exists else 404).
You can move the WebAPI controllers into separate project if there is really a choice that the service could be consumed from different clients else avoid doing that. Once you move the WebAPI controllers into a separate project then you will face Cross-Domain issues when you try to consume it from the javascript in MVC project.
Point 1:
It is logical to return the entity from actions in case of Web API but then we cannot control the HttpResponseMessage properties (like HttpStatusCode). Except that returning an entity is always a cleaner approach. We can control serialization, formatting etc in respective filters to get our job done. But you can never return car/HttpResponseMessage optionally as compiler will not let you compile a method with return type as HttpResponseMessage and return type Car.
Point 2:
Having separate controllers for view and rest calls is a good idea. I would suggest to have controllers with the same name but in different namespaces and then routes handle http calls separately (but prepending '/api/' to the rest calls. Having different actions in the same controller for ViewResult and HttpResponseMessage/Car is an option also but not as clean and separate.