I'm starting MVC and I understand the difference between models and ViewModels, thanks to this post:
http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp.net-mvc-applications
However I showed this to my colleague and am now under the impression that this is an alternative to using knockout to bind views to models. Can someone explain this? Does knockout binding do the same thing as defining a ViewModel class with properties?
Thank you!
In convention you can use Knockout view-model is as client-side and MVC view-model is as server-side.
Your question : How do you decide which to use ?
Answer : You can use both as parallel.That means for your single cshtml page can have a knockout view-model is as below.It contains both properties and functions as a unit.This view-model for the behavior what you need for the client side functionality.
//This is a simple Viewmodel
//JavaScript that defines the data and behavior of your UI
function AppViewModel() {
var self = this;
self.firstName = ko.observable();
self.lastName = ko.observable();
self.fullName = ko.computed(function () {
return self.firstName() + " " + self.lastName();
});
self.capitalizeLastName = function () {
var currentVal = self.lastName();//Read the current value
self.lastName(currentVal.toUpperCase());//Write back a modified value
};
}
But for show server side behaviors you can use more complex (or more properties) with the MVC view-model.That is for bring data from database and show those data in your view.
Conclusion: So you can use both view-models simultaneously when working with MVC.
Important Note : But if you need to use single view-model for both scenarios then you can do that thing also.For that you have to use KnockoutJS Mapping plugin.
It can be used like below.
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script type="text/javascript">
$(function() {
var viewModel = ko.mapping.fromJS(#Html.Raw(Model.ToJson()));
ko.applyBindings(viewModel);
});
</script>
You can get more details about this from Loading KnockoutJS View Models from ASP.Net MVC, for faster page loads
If you need to know more about Knockout check learn.knockoutjs
I hope this will help to you.
Knockout view models are client side and MVC is server side, that is the big difference.
Knockout allows you to create single page applications, and encapsulates logic on the client side.
ViewModels in MVC only works server side for rendering the page and handle postbacks.
Xharze answer is valid, but...
If you need to add view related logic to your Business entities that can not be done Client side then you need to have server side View models. If not they become redundant.
There is still a difference to classic MVC, these server side models will not be used to render server side content, they will be exposed to the client side KO engine using REST
Related
I am asp.net Web Forms developer and i know the basics of Asp.net MVC. Developers talk about advantages of MVC but I haven't come across a clear or compelling description for using MVC over Asp.NET.
This is not duplicate question and i have gone through almost all
similar question but did not get clear description more in relation
with real life example. I do appreciate and expect the explanation of
each and every question mentioned below with real life example please
don't mark it as duplicate.
I know that you can not replace Asp.NET Web Forms with Asp.NET MVC still we have following advantages in MVC:
Separation of concerns (SoC): We can achieve it in asp.net also by adding BAL component in fact in MVC we do have to isolate business logic from controller action methods.Is SoC only applicable for Model-View-Controller separation in MVC? then what about business logic. Please provide real life example which will consider both Web Forms and MVC.
Enable full control over the rendered HTML: Web Forms also provide control over Html isn't it? Its considered that html rendering in Web Forms is more abstracted then what does html helper methods do in MVC. Anybody please explain it with example considering both Web Forms and MVC as i am getting more confused over this point.
Enable Test Driven Development (TDD): If you have separated your Business logic into BAL then you have achieved TDD? Is there any scenario where MVC would be accurate choice over webforms? Please provide example for same
No ViewState and PostBack events: We can manage viewstate in Web Forms which comes with cost of efforts, since in MVC we can maintain state by using Viewbag,Tempdata as web is stateless there is some mechanism that MVC maintains its state as hidden fields for Web Forms then how MVC Improves performance and page size in terms of statefullness? Example by considering Web Forms and MVC appreciated
Easy integration with jQuery: "Asp.NET Web Forms generate its custom id for controls" this is the only consideration for ease of integration of JavaScript frameworks? if yes then we can use ClientIDMode in asp.net control in Web Forms
1. Separation of concerns
SoC in MVC is not about separation business logic from UI. More importantly, it gives Controller main functions:
to fill View Model from Domain Model;
to handle View activity;
to show views depending on Domain logic.
View is responsible only for data representation in MVC.
It makes testing very simple as Controller operates pure View Model classes, opposed to WebForms which operates events and Form.
In WebForms View handles all UI activity and it basically makes decisions about scenario flow.
Here I'd like to mention that terms of View Model and Domain Model are different. Domain Model is a term describing all the services, Business logic and DAL hidden from Controller with some facade. And View Model is a class that encapsulates data required by View. It may be shared by Domain Model in simple cases. Why two classes?
Here are similar code snippets of ASP.NET MVC and WebForms doing the same things: 1) get data 2) handle data submission. In both cases I assume that IDomainModel is injected.
MVC:
public class SomeController : Controller
{
// injected
public IDomainModel Domain { get; set; }
public ViewResult Edit()
{
var record = Domain.GetRecord(1);
var dictionary = Domain.GetSomeDictionary();
var model = new SomeViewModel(record, dictionary);
return View(model);
}
[HttpPost]
public ActionResult Edit(SomeViewModel model)
{
if (ModelState.IsValid)
// save
return RedirectToAction("Result");
else
return View(model);
}
}
WebForms:
public partial class SomePage : System.Web.UI.Page
{
// injected
public IDomainModel Domain { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var record = Domain.GetRecord(1);
var dictionary = Domain.GetSomeDictionary();
RecordId.Text = record.Id.ToString();
RecordName.Text = record.Name;
RecordDescription.Text = record.Description;
DicValue.DataSource = dictionary;
DicValue.DataValueField = "Id";
DicValue.DataTextField = "Value";
DicValue.SelectedValue = record.DictionaryEntryId.ToString();
DicValue.DataBind();
}
protected void btnSave_Click(object sender, EventArgs e)
{
var record = new RecordModel
{
Id = Int32.Parse(this.RecordId.Text),
Name = this.RecordName.Text,
Description = this.RecordDescription.Text,
DictionaryEntryId = Int32.Parse(this.DicValue.Text)
};
// save
}
}
Testing MVC controller Edit GET is incredibly simple:
[TestMethod]
public void EditGetTest()
{
SomeController target = new SomeController();
var record = new RecordModel { Id = 1, Name = "name1", Description = "desc1", DictionaryEntryId = 1 };
var dictionary = new List<SomeDictionaryEntry>
{
new SomeDictionaryEntry { Id = 1, Value = "test" }
};
target.Domain = new SimpleMVCApp.Models.Fakes.StubIDomainModel()
{
GetRecordInt32 = (id) => { return record; },
GetSomeDictionary = () => { return dictionary; }
};
var result = target.Edit();
var actualModel = (SomeViewModel)result.Model;
Assert.AreEqual(1, actualModel.Id);
Assert.AreEqual("name1", actualModel.Name);
Assert.AreEqual("desc1", actualModel.Description);
Assert.AreEqual(1, actualModel.DictionaryEntryId);
}
To test WebForms events we need to make a lot of changes and assumptions: we need to make the methods public, we need to initialize Form and its controls. It results in heavy hard-read tests which are impossible for 3) TDD.
2. Enable full control over the rendered HTML
I think this statement is a little bit exaggeration. Only HTML can give full control over rendered HTML. As for HtmlHelpers, DisplayTemplates and EditorTemplates, though the team made major improvements over 6 versions of the framework, it's still sometimes annoying to transform additionalViewData into html attributes.
For example, to pass some html attributes to an input you can't use #Html.EditorFor, you'll have to use #Html.TextBoxFor.
In the same time in ASP.NET you can specify any attributes on any elements and they will just render.
MVC:
Wrong:
#Html.EditorFor(m => m.Name, new { MySuperCustomAttribute = "Hello" })
Correct:
#Html.TextBoxFor(m => m.Name, new { MySuperCustomAttribute = "Hello" })
ASP.NET:
<asp:TextBox runat="server" ID="RecordName" MySuperCustomAttribute="hello"></asp:TextBox>
3. Enable Test Driven Development (TDD)
I think this statement is about testing of Controller vs Code-Behind. I covered this in 1.
4. No ViewState and PostBack events
ViewBag and ViewData are weak-typed facilities to pass data between Controller and Views. They are rendered as elements, nothing similar to ViewState. For example, in my View I initialize ViewBag.Title = "EditView"; which allows me to use this string on the Layout Page: <title>#ViewBag.Title - My ASP.NET MVC Application</title>. On the page it looks just like this <title>EditView - My ASP.NET MVC Application</title>
As to TempData, Session and Application, they are stored on server side. It's not rendered to page at all.
5. Easy integration with JQuery
I don't see how integration with JQuery becomes easier for MVC. Here is how we integrate JQuery into WebForms:
<script src="Scripts/jquery-1.8.2.min.js"></script>
<script>
$(document).ready(function () {
$('#DicValue').change(function () {
$('#ChosenValue').text($('#DicValue option:selected').val());
});
});
</script>
And here is almost the same snippet for ASP.NET MVC:
#section scripts{
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script>
$(document).ready(function () {
$('#DictionaryEntryId').change(function () {
$('#ChosenValue').text($('#DictionaryEntryId option:selected').val());
});
});
</script>
}
There is another point to mention about JQuery here: as ASP.NET MVC is pretty Opinionated framework, it becomes somewhat restrictive for extensive JS usage. It was originally designed for Scaffold Templates based development, and it is best with it. JQuery is good for ajax requests and for some minor logic in ASP.NET MVC, but when you start using it extensively, you end up with two controllers for every view: a C# one and a JS one. Hello, Unit Testing! Also JQuery(UI) is very good with its rich set of UI controls.
ASP.NET is designed with Postbacks in mind and they dictate you the basic application model. However, there are also different UI Toolkits for ASP.NET to make an application more dynamic and there is still some place for JQuery.
Wow, that was a long answer. Hope it'll help.
Ok.
I am developing applications in both frameworks i.e. Webforms and MVC, will be explaining things based on my experience.
Discipline is the most important thing that needs to be followed with any Architecture you are working on.
If you follow MVC correct and as per standards life would be super simple.
Lets go point by point.
Separation of concerns (SoC):
MVC provide Clean, organized and granular solution at various levels e.g.
There are multiple helper classes which hooks and does help in late bindings, you can mock controller using various plugins.
Easy to develop Helper classes.
Enable full control over the rendered HTML
Basically in MVC we have HTML in its native format, so you have more control over it and how it matters is it speeds up Page Load when you have lot of controls and data that are coming on the page.
And it matters when we are going with Web form architecture.
Enable Test Driven Development (TDD):
With discipline you can do it in both Architecture
No ViewState and PostBack events:
Viewstate puts extra load on page and in web forms when you see source of a page having lots of controls, grid etc, you will see huge viewstate.
If there is no viewstate life is just simple.
ViewData is at client side whereas others are at server side.
Easy integration with Jquery:
Indeed, MVC3, 4 have super better support for JQuery. There are lot of Predefined JQueries that are already introduced in templates.
Other than above points some additional points
Bundling
Refreshed and modernized default project templates
Better support of Mobile applications
Fast development
Code reusability
Least coupling within Layers
Good support to Ajax
Have a look at few links
http://www.codeproject.com/Articles/683730/New-Features-in-ASP-NET-MVC
http://www.asp.net/mvc/tutorials/hands-on-labs/whats-new-in-aspnet-mvc-4
Difference between ASP.NET MVC 3 and 4?
Here is the official answer from Microsoft for this question: http://www.asp.net/get-started/websites
I'd add to the top answers (which are generally correct) than MVC (and Web Pages) are both open source, so you have an easy access to the source code, bug database and can even PR bug fixes or features back (which we have taken in abundance).
At the end of the day it's a personal choice, and also depends on the experience you and your team has and if you have legacy code you want to reuse.
The MVC framework does not replace the Web Forms model; you can use either framework for Web applications. (If you have existing Web Forms-based applications, these continue to work exactly as they always have.)
Before you decide to use the MVC framework or the Web Forms model for a specific Web site, weigh the advantages of each approach.
Advantages of an MVC-Based Web Application
The ASP.NET MVC framework offers the following advantages:
It makes it easier to manage complexity by dividing an application into the model, the view, and the controller.
It does not use view state or server-based forms. This makes the MVC framework ideal for developers who want full control over the behavior of an application.
It uses a Front Controller pattern that processes Web application requests through a single controller. This enables you to design an application that supports a rich routing infrastructure.
It provides better support for test-driven development (TDD).
It works well for Web applications that are supported by large teams of developers and for Web designers who need a high degree of control over the application behavior.
Advantages of a Web Forms-Based Web Application
The Web Forms-based framework offers the following advantages:
It supports an event model that preserves state over HTTP, which benefits line-of-business Web application development. The Web Forms-based application provides dozens of events that are supported in hundreds of server controls.
It uses a Page Controller pattern that adds functionality to individual pages.
It uses view state on server-based forms, which can make managing state information easier.
It works well for small teams of Web developers and designers who want to take advantage of the large number of components available for rapid application development.
In general, it is less complex for application development, because the components (the Page class, controls, and so on) are tightly integrated and usually require less code than the MVC model.
Source http://msdn.microsoft.com/en-us/library/dd381412(v=vs.108).aspx
I'm writing a web application that will mainly use AngularJS for its modularity and testability and ASP.NET MVC server side technologies for model validation.
The idea is to load PartialViews in ng-views in order to asynchronously load only specific logic parts. So the question is: how to better pass server-side objects to AngularJS controllers? A silly hack that comes to mind is to print things in the PartialView such as:
window.myValue = 42;
and then get it back from the controller with the $window service injected:
$scope.myValue = $window.myValue
This is not feasible, though, as ng-view loadings strip out every <script> tag before inserting the partial content into the DOM.
I have noticed that there is the ng-init directive, should I rely on that one alone? Generally speaking, what are the best practices for making these two parts work with each other?
Thanks.
If you are unable to use a REST service (best option) you can easily do exactly what you suggest in your question but perhaps in more modular way. You can encode your view's model and place it in a global variable and then have a service that pulls this out:
Here is an example:
<body ng-controller="MainCtrl">
<div>ID: {{data.id}}</div>
<div>Name: {{data.name}}</div>
<script type='text/javascript'>
// mystuff = #Html.Raw(Json.Encode(Model)); Encode the model to json
mystuff = { id: 1, name: 'the name'};
</script>
</body>
app.controller('MainCtrl', function($scope, DataService) {
$scope.data = DataService.getData('mystuff');
});
app.factory('DataService', function($window) {
var service = {}
service.getData = function(data) {
if ($window[data] !== undefined)
return $window[data];
else
return undefined;
}
return service;
});
Demo: http://plnkr.co/edit/jqm2uT3kbDm2U30MCf48?p=preview
You'd might want to create a standardized model that you use in all of your pages. This is a bit hacky and a REST service is your best option as others have stated.
I ended up using the ng-init directive.
Luckily, I got to restructure the Web application and go for a single page, client-side, application based on Web services only.
When, if ever, is it appropriate to render an angular partial view using Razor?
I've generally tried to stay away from mixing server side rendering with client-side rendering when using Angular but I have found it convenient to sometimes:
Set variables/data that is known server-side
An example might be a client API key that you might want to use client-side without making an additional call to a backend for that information.
Here is an example of a template:
<div config="{ soundcloudApiKey: '#soundcloudApiKey' }">
</div>
Where #soundcloudApiKey is presumably available in a model server-side and config is a directive that brings data from the markup into your Angular code in case you want to use it elsewhere:
myModule.directive('config', function() {
return {
link: function(scope, elm, attrs) {
// you can save config to a service and use it elsewhere
var config = scope.$eval(attrs.config);
console.log(config.soundcloudApiKey);
}
};
});
Note: there is likely a cleaner way to get to this type of configuration data like via a login process or an explicit call for config settings but I've used this type of thing in the past and it works just fine!
I am starting a new project, and keen to make use of the KnockoutJS + Web Api which are new to me, I have a good understanding of the Web Api, but Knockout is tough to get my head around at the moment.
This is my initial thoughts of how I want my app to work:
I have a standard MVC controller such as LeadsController
LeadsController has an Action called ListLeads, this doesn't actually return any data though, but just returns a view with a template to display data from Knockout.
The ListLeads view calls my api controller LeadsApiController via ajax to get a list of leads to display
The leads data is then mapped to a KnockoutJs ViewModel (I don't want to replicate my view models from server side into JavaScript view models)
I want to use external JavaScript files as much as possible rather than bloating my HTML page full of JavaScript.
I have seen lots of examples but most of them return some initial data on the first page load, rather than via an ajax call.
So my question is, how would create my JavaScript viewModel for Knockout when retrieved from ajax, where the ajax url is created using Url.Content().
Also, what if I need additional computed values on this ViewModel, how would I extend the mapped view model from server side.
If I haven't explained myself well, please let me know what your not sure of and I'll try and update my question to be more explicit.
I think your design is a good idea. In fact, I am developing an application using exactly this design right now!
You don't have to embed the initial data in your page. Instead, when your page loads, create an empty view model, call ko.applyBindings, then start an AJAX call which will populate the view model when it completes:
$(function () {
var viewModel = {
leads: ko.observableArray([]) // empty array for now
};
ko.applyBindings(viewModel);
$.getJSON("/api/Leads", function (data) {
var newLeads = ko.mapping.fromJS(data)(); // convert to view model objects
viewModel.leads(newLeads); // replace the empty array with a populated one
});
});
You'll want to put a "Loading" message somewhere on your page until the AJAX call completes.
To generate the "/api/Leads" URL, use Url.RouteUrl:
<script>
var apiUrl = '#Url.RouteUrl("DefaultApi", new { httproute = "", controller = "Leads" })';
</script>
(That's assuming your API route configured in Global.asax or App_Start\RouteConfig.cs is named "DefaultApi".)
The knockout mapping plugin is used above to convert the AJAX JSON result into a knockout view model. By default, the generated view model will have one observable property for each property in the JSON. To customise this, such as to add additional computed properties, use the knockout mapping plugin's "create" callback.
After getting this far in my application, I found I wanted more meta-data from the server-side view models available to the client-side code, such as which properties are required, and what validations are on each property. In the knockout mapping "create" callbacks, I wanted this information in order to automatically generate additional properties and computed observables in the view models. So, on the server side, I used some MVC framework classes and reflection to inspect the view models and generate some meta-data as JavaScript which gets embeded into the relevant views. On the client side, I have external JavaScript files which hook up the knockout mapping callbacks and generate view models according the meta-data provided in the page. My advice is to start out by writing the knockout view model customisations and other JavaScript by hand in each view, then as you refactor, move generic JavaScript functions out into external files. Each view should end up with only the minimal JavaScript that is specific to that view, at which point you can consider writing some C# to generate that JavaScript from your server-side view model annotations.
For the url issue add this in your _Layout.cshtml in a place where it is before the files that will use it:
<script>
window._appRootUrl = '#Url.Content("~/")';
</script>
Then you can use the window._appRootUrl to compose urls with string concatenation or with the help of a javascript library like URI.js.
As for the additional computed values, you may want to use a knockout computed observable. If that is not possible or you prefer to do it in .Net you should be able to create a property with a getter only, but this won't update when you update other properties on the client if it depends on them.
Before I start, I want to make it clear that my code is working properly, and this is more of a "general best practice" question. I'm using knockout.js to load in my ASP.NET MVC2 model into knockout's viewModel.
In my aspx page I have:
<script>
var model = <%= new JavaScriptSerializer().serialize(Model) %>;
// the above line will display in my page's "View Source". Is this bad? slow?
</script>
Then in my JavaScript include file at the top I have:
$(document).ready(function() {
var viewModel = new MyViewModel();
ko.applyBindings(viewModel);
viewModel.modelProp(model);
});
The code totally works fine, but the concern I have with this is that the JSON output is viewable in the "View Source" option from the browser in the HTML output. I'm curious about two things:
Does this also happen in ASP.NET MVC3? I'm using ASP.NET MVC2, hence I can't use #Html.Raw(Json.Encode(Model)); -- But does the MVC3 method result in the same issue?
Is this something I should be concerned about? Is it a security issue? Is it a performance issue? The page's source will be larger because I'm outputting the JSON into a JavaScript variable, no? Again, maybe it's not an issue in MVC3?
If I hear you correctly, you want to now if you should be concerned that people can see your json. I would not be concerned about that. In fact, not only can they see the json by viewing source, but they can also see it via a network sniffer like fiddler, httpwatch, or browser developer tools (F12). I'm not sure why you care if the json is visible because once it gets data bound to the UI, it will be there too.
As a side note, by loading your KO viewmodel from MVC, that means your viewmodel will only refresh its model data when you post. If you load it via an ajax call (to perhaps an MVC action since you use asp.net mvc) you could avoid that page refresh. Just another option.