accessing model from controller, is it a good way? - c#

i came across few blogs and forums and found this way of interacting with MODEL class from controller using LINQ to SQL
is it a proper way to access ?
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
var dataContext = new MovieDataContext();
var movies = from m in dataContext.Movies
select m;
return View(movies);
}
}
}

For small-time projects and tutorials this is just fine and the recommended approach.
Small tip: You could wrap the MovieDataContext in a using statement which takes care of closing the connection and releasing resources:
using (var dataContext = new MovieDataContext())
{
// query...
}
Keep in mind when using this, you can't lazy-load properties in your view anymore since the data context is closed when the object is sent to the view. So a query like movie.Director.Name won't work, unless you eager-load it.

Yep, that should be the standard way of using the MVC pattern.

It is not necessarily bad, but you can improve on it by applying well known patterns and best-practices, i.e. layering, repositories, etc.
Ideally, it is good to keep the controller as thin as possible and delegate all database operations or whatever logic required on the lower levels, like a service layer for instance.

Related

Questions about good practices with MVC and Entity Framework

I'm trying to build a simple MVC application with VS and Entity Framework, i have few questions.
I want to add some default values to my model, i can do that by
including default values to constructor like this:
public Worker()
{
WorkerActive = true;
}
But default controller code is like this, and it's not returning anything
public ActionResult Create()
{
return View();
}
If i change that to this, it works but i'm not sure if i'm doing something wrong:
public ActionResult Create()
{
return View(new Worker());
}
Are there any problems here?
I have a combobox with all workers in it, i want to show some
records based on the selection. For example, i want to show all
records where WorkerId=ComboboxValue. I can do this easily
by using this:
workers = m.Workers.Where(w => w.BranchId == curUser.BranchId).ToList<Worker>();
But it's in a view. Is using
statements like where in view a bad practice? I can add a new method
to controller like getUsersByBranch(BranchId) and use that.
What's the right way to do it?
Thanks
1) I'd argue that your models should be as stupid as possible, just properties and metadata. Your controller can certainly have logic in it to manipulate the model, though. That's what it's for - to return the model to the view, however you see fit:
public ActionResult Create()
{
var model = new Worker { WorkerActive = true };
return View(model);
}
Plus, you won't have to worry about needing different default values in a different controller.
2) The view is 'supposed' to be pretty dumb too. But as with all best practices, it really comes down to the overhead of refactoring and the potential gain. No, that code probably shouldn't be in your view. Ideally, if it's required by the view, it'd be a property of some sort on your model, that you controller has set up.
The logic with the 'best practice' of simple views is that it can get overly convoluted very quickly if you keep doing this, leading to spaghetti code. But like I said, you should try things and see if you like them sometimes, instead of simply going along blindly with best practices.
by 'property on your model' I mean:
public class CreateModel
{
public List<User> UsersInBranch { get; set; }
}
then your controller can fill it in, like above. Keeps your view cleaner, and lets the controller perform it's intended functionality. With MVC and Razor, logic in your view is not really in your view (in my mind), because it's still running server side. It feels like mixing server and client side operations to me.
public ActionResult Create()
{
return View(new Worker());
}
No problems in here, but Worker is a Entity? Maybe you should separate infrastructure (ef mapping) code from presentation (mvc).
workers = m.Workers.Where(w => w.BranchId == curUser.BranchId).ToList<Worker>();
Don't do this in your View. It would be better if you move this code to repository. Take a look at the good paper from Martin Fowler about this pattern:
http://martinfowler.com/eaaCatalog/repository.html

Lambda expression error in MVC4

Firstly I would like to apologize to you all because I know that this question has been asked a whole bunch of times. But I dont know much about MVC or .NET or Lambda expressions per se. I am working on a small project and I am stuck at the Lambda expression error as below
EDIT
Below is the controller Code
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVC4Trial.Models;
using Kendo.Mvc.UI;
using Kendo.Mvc.Extensions;
namespace MVC4Trial.Controllers
{
public partial class CallTrackController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Remote_Data()
{
return View("AjaxBinding");
}
public ActionResult vwCallDetails([DataSourceRequest] DataSourceRequest request)
{
return Json(GetCallDetailsFn().ToDataSourceResult(request));
}
private static IEnumerable<CallDetails> GetCallDetailsFn()
{
var callData = new CallTrackClassDataContext();
return callData.CallDetails.Select(calldetail => new CallDetails
{
CCCID = calldetail.CCCID,
Mp3_Url = calldetail.Mp3_Url,
Index = calldetail.Index,
Target_Number = calldetail.Target_Number,
Duration = calldetail.Duration,
LocalTime = calldetail.LocalTime,
Site_Name___Address = calldetail.Site_Name___Address,
Ad_Source_Name = calldetail.Ad_Source_Name,
Tracking_Number = calldetail.Tracking_Number,
Caller_Number = calldetail.Caller_Number,
Available_Feature = calldetail.Available_Feature
});
}
}
}
I would like to learn how to fix this error. What am I missing here? Do I need to make any sort of changes on my Model/View/Any other file? Thanks for reading and helping.
There's something wrong with Duration. It's underlined in red, indicating that it doesn't exist on the class, or some other issue is causing it to not be recognized. Since there's an error here, the lambda expression doesn't process properly and it's only then that Visual Studio recognizes there error. Essentially, the reported error is masking the true problem. Fix Duration or remove it, and the lambda expression will be fine.
For what it's worth though, what you're doing doesn't make much sense. callData.CallDetails already returns an instance of CallDetails (or at least it should, or you should change the name), so using Select to return an instance of CallDetails populated from an instance of CallDetails is superfluous.
UPDATE
Sorry for not being more clear. My last comment really depends on what is exactly going on in code I can't see. So there's two possible scenarios:
1) callData.CallDetails is an instance of CallDetails. If this is the case, using Select is a waste of time and code because all you're doing is just converting one instance of CallDetails to another. Just doing return callData.CallDetails; would have the same effect.
2) callData.CallDetails is not an instance of CallDetails. If this is the case, then you should simply rename the CallDetails member of callData to avoid the sort of confusion that prompted my comment in the first place.
FWIW: If you really need to map some other type to an instance of CallDetails like this, you should look into AutoMapper. Writing this code is not only repetitive and time-consuming, but you also make yourself more prone to errors. For example, what if you later change the definition of CallDetails? You now got to track down every explicit mapping like this and change that as well, whereas with AutoMapper, you likely can just change the definition and be done.

Get data in controller using context or create method?

Which of the following is the correct, or at least the best one:
Create a method to retrieve data in controller:
public ActionResult Index()
{
var list = _context.MyClass.Take(10);
return View(list);
}
or use context directly:
public ActionResult Index()
{
var list = MyClass.MethodWrapperToGet(10);
return View(list);
}
My concern with the first is that the database is too exposed; making it too easy for developers to misuse.
It really depends on the size of your project. For something small or a quick prototype I'd go with the option where controllers access the DbContext directly.
public ActionResult Index()
{
var list = _context.MyClass.Take(10);
return View(list);
}
I personally prefer separating concerts. In other words, I would create a service class that hands the controller exactly the data that it needs. Remember that the Controller should not know how to execute tasks but instead what needs to be executed after what.
This of course, does not mean you have to implement the repository pattern. Your service class could access the DbContext directly if you would like to.
Ideally you use a variation of exposing _context where you could pass that context through Dependency Injection so you can Unit Test your controller.
Static calls are very hard to test, at least in .Net

MVC3 Partial Views

Still Learning MVC3, EF. For now I am connecting to MySql but I believe that will not be relevant. For simplicity, I decided to use one database for my test application and I have included a category to differentiate the data. For eg I have a news, events,info and pages categories. Now when it comes to listing contents in views for example at the homepage, I want to list latest 5 news items(news category), latest 5 events(events category), welcome text(info category). i have been able to create partialViews to list these at the different sections of the homepage. But I feel am doing this wrongly since in each of these PartialViews I am querying the same table over and over and just filtering with where cat=....in the LINQ query.
Can you please confirm if that should be the practice or there is a better way to do this.
You could do the following:
Controller:
public ActionResult Home()
{
IEnumerable<MyDateRecords> myData = LinqQueryToGetAllTheDataUnFiltered();
ViewData.Model = new MyViewData { MyData = myData; }
return View();
}
ViewModel class:
public class MyViewData
{
List<MyDataRecords> MyData { get; set; }
List<MyDataRecords> News { get { return MyData.Where(m => m.Category = "News"); } }
List<MyDataRecords> Events { get { return MyData.Where(m => m.Category = "Events"); } }
}
View:
#model MyViewModel
#Html.Partial("NewsPartial", Model.News)
#Html.Partial("EventsPartial", Model.Events)
Partial:
#model IEnumerable<MyDataRecord>
This way we only queried for the data once and just passed a different set to each partial
For an uncomplicated way of presenting this type of data, what you are doing is fine. You should look at the OutputCacheAttribute for any PartialView Method you use on your Controller.
This is pretty inefficient. But it's good that you noticed this because querying that database is often the bottleneck in any given request.
For starters you should retrieve that data into a dictionary or model and then pass it to the partial views to render similar to what Bassam outlined. Ideally, this should be taken care of in the Controller to stick to the MVC paradigm and then passed to the main view, which would then pass the appropriate data to the partial views.
Once you get more advanced/familiar with ASP.NET MVC, you can start looking into caching. I'd stay away from caching for right now since it get somewhat tricky if you have data that is rapidly changing since you need to start worrying about updating/synchronizing/etc.

Using MVC, how do I design the view so that it does not require knowledge of the variables being set by the controller?

Let's say I have a theoretical MVC framework that uses a ViewData object to pass data from the controller to the view. In my controller, let's say I have some code like this (in pseudocode):
function GetClientInfo()
{
// grab a bunch of data from the database
var client = Database.GetClient();
var clientOrders = Database.GetClientOrders();
var clientWishList = Database.GetClientWishList();
// set a bunch of variables in the ViewData object
ViewData.set("client", client);
ViewData.set("clientOrders", clientOrders);
ViewData.set("clientWishList", clientWishList);
showView("ClientHomePage");
}
And then in my ClientHomePage view, I display the data like so:
<p>Welcome back, [ViewData.get("client").FirstName]!</p>
<p>Your order history:</p>
<ul>
[Html.ToList(ViewData.get("clientOrders")]
</ul>
<p>Your wishlist:</p>
<ul>
[Html.ToList(ViewData.get("clientWishList")]
</ul>
This is what I understand MVC to be like (please correct me if I'm wrong). The issue I'm having here is those magic strings in the view. How does the view know what objects it can pull out of the ViewData object unless it has knowledge of what the controller is putting in there in the first place? What if someone does a refactor on one of the magic strings in the controller, but forgets to change it in the view, and gets a runtime bug instead of a compile-time error? This seems like a pretty big violation of separation of concerns to me.
This is where I'm thinking that a ViewModel might come in handy:
class ClientInfo
{
Client client;
List clientOrders;
List clientWishList;
}
Then the controller creates an instance of ClientInfo and passes it to the view. The ViewModel becomes the binding contract between the controller and the view, and the view does not need to know what the controller is doing, as long as it assumes that the controller is populating the ViewModel properly. At first, I thought this was MVVM, but reading more about it, it seems like what I have in mind is more MVC-VM, since in MVVM, the controller does not exist.
My question is, what am I not understanding here about MVC vs. MVVM? Is referring to variables in the ViewData by magic strings really not that bad of an idea? And how does one insure that changes made in the controller won't adversely affect the view?
Your understanding of MVC is wrong, it stands for Model View Controller but you are missing the Model in your example. This is the typed entity that gets passed back to the View to do the rendering. In ASP.Net MVC you would use typed Views that also type the Model within the View so it is checked at compile time. This eliminates the need for magic strings (second part of your question).
In MVVM you have Model View ViewModel. This is a way of binding a ViewModel directly to the UI layer via a View which is used a lot in WPF. It replaces the need for a controller and it's generally a 1-to-1 mapping with the UI. It's just an alternative mechanism that solves the same problem (of abstraction and seperation of concerns) but better suited to the technology.
Theres some useful info here which might help understand the difference.
Best approach to use strongly typed views
Models:
public class ContentPage
{
public string Title { get; set; }
public string Description { get; set; }
}
public class ContentPagesModel
{
public ContentPage GetAboutPage()
{
var page = new ContentPage();
page.Title = "About us";
page.Description = "This page introduces us";
return page;
}
}
Controller:
public ActionResult About()
{
var model = new ContentPagesModel();
var page = model.GetAboutPage();
return View(page);
}
View:
#model Experiments.AspNetMvc3NewFeatures.Razor.Models.ContentPage
#{
View.Title = Model.Title;
}
<h2>About</h2>
<p>
#Model.Description
</p>
for more detail check out here
I case of using string as keys of ViewData - yes, it will be a lot of exceptions if someone will refactor code.
It sounds like your understanding of MVC is very old, probably based on MVC 1. Things have changed tremendously in the last couple of years.
Now we have strongly typed view models, and we have the ability to use expressions in the view, which by default aren't compile-time validated, but they can be for debug purposes (though it slows down the build a great deal).
What's more, we don't pass model data through ViewDate anymore (well, not directly anyways.. it's still passed that way but the framework hides it).

Categories