I've been told that MVC 1.0 TempData does not work under a load balancer when using SQL Server and that it is because the Dictionary itself is not serializable.
We require this for a project and are looking to be able load balancer effectively.
So I would be very grateful if someone could answer the following questions:
Is there away around this so you can make it work?
Is this fixed in MVC 2.0?
Can we create a ITempDataProvider to fix it?
Or has anyone made a fix to the source code for a project of their own they would like to share?
Cheers,
Jamie
The dictionary itself doesn't need to be serializable. It is what you store inside TempData that needs to be serializable. So for example if you have the following class
[Serializable]
public class Foo
{
public string Bar { get; set; }
}
You can perfectly fine use SQL server for session persistence and write the following code:
TempData["foo"] = new Foo { Bar = "bar" };
Session["foo"] = new Foo { Bar = "bar" };
Mmmm, so any UI model (ASP.Net MVC) would just require the Serializable attribute and that should just work?
How does it work for lists and collection based UI models?
Related
I overtook a project which was developed by a company for us, unfortunately we do not get much support and in the long term, we should accomplish maintainence by ourselves for it. The application consists of a simple Web client (HTTP, JavaScript, Knockout Framework) and a REST API Service (.NET 4.5, ASP.NET MVC I guess).
Currently I am only modifiying the client, so the Server should still work as expected.
On the clientside I modified the Knockout View Model a little bit (added some computables and optimized presentation of some values). The View Model consists of 'Issues' and 'Comments' (as an array on issues, its an Bug tracker in fact). If I create a new issue, description is added to a first comment, the whole Model is JSON.stringified and the send to the .NET API Service. I prooved with Firebug, that the JSON that gets posted looks like this:
{
"Id":0,
"Title":"THis is a title",
"Comments":[
{
"Id":1,
"Text":"this is the first comment"
}
]
}
On the client side, I have a "IssueController":
[HttpPost]
public HttpResponseMessage PostIssues( Issue issue ) {
//issue should already hold the deserialized content of the JSON here,
//but it only contains 'Id' and 'Title' not the 'Comments' (empty List)
...
}
The issue domain model object also has an array for holding comments, but on this end its empty already. The .NET code doesn't have any part which explicitely parses the JSON, as far as I understood it, the MVC Framework does this implicitely by equal property names (Is that right?).
The deserialization already worked as expected, so the .NET Code should be fine, but I looks like that I have modified the JSON in a way, that this implicit mapping of comments does not work anymore. Unfortunately I dont have much experiences with the .NET MVC Framework (or is it just the .NET WebAPI Framework, cannot even tell you that).
These are my questions:
What kind of .NET REST API Framework is that? How can I distinguish?
How is this implicit JSON deserialization working, and what are its pitfalls, for example when portions of the JSON doesn't get deserialized as expected? Especially on the client side (as I said, I didn't modify the server code)
Any ideas about what I could have done to the JSON, that the server doesn't like it anymore? ;)
EDIT
Issue.cs looks like this (simplified for sure):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Bo;
using Projects.DomainObjects;
namespace Projects.Models {
public class Issue : DomainObject {
public Issue() {
this.Comments = new List<Comment>();
}
public long Id { get; set; }
private string _Title;
public string Title { get { return _Title; } set { _Title = value; NotifyChanged(); } }
public List<Comment> Comments { get; set; }
}
Comment.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Common;
using Projects.DomainObjects;
namespace Projects.Models {
public class Comment : DomainObject {
public Comment() {
}
public long Id { get; set; }
public string Text { get; set; }
}
I just tried to your code straight from your post and it worked for me.
So there are a few things that may be going wrong on your side:
When you post the object to the server, make sure you are converting back from Knockout observable to a json object. So in your ajax request, make sure it looks like: data: ko.toJSON(issue) and not just data: issue.
When you post the object to the server make sure you sent header content-type: application/json
Here are the answers to your other questions:
What kind of .NET REST API Framework is that? How can I distinguish?
This doesn't look like anything custom (at least, what you posted) it is just straight Web API in .NET.
How is this implicit JSON deserialization working, and what are its pitfalls, for example when portions of the JSON doesn't get deserialized as expected? Especially on the client side (as I said, I didn't modify the server code)
Deserialization on the server uses the collection of formatters that work based on the content-type set by the client. This can get complex if you want to customize it but there is information here
Any ideas about what I could have done to the JSON, that the server doesn't like it anymore? ;)
As I said your code worked for me!
Solved it, the Problem was a computed that returns a sorted array of the comments. So my knockout model contains an
self.Comments = ko.observableArray([]); //...which gets filled with the comments of an issue
and a
self.CommentsSorted = ko.computed(function() {...}); //...which simply returns a sorted Comments array
So when I serialize this model, the posted JSON now represents the Comments Array, but also the CommentsSorted Array. Only when I do
var i = ko.toJS(issue);
delete i.CommentsSorted;
before I post i as data, .NET is able to deserialize Comments correctly.
The mysterious thing about this is, that there were always other computed fields in my knockout model, which get ignored completely by .NET and do not disturb deserialization in any way. So it seems that it depends mainly on the name and type of the fields in the model (perhaps if the first letters are equal?).
The good thing: it works now
The bad thing: it isn't really deterministic how .NET does the deserialization of JSON data and I am also not able to debug if it doesn't behave as expected.
I have one issue I am trying to resolve for days now, but I can’t get the right approach.
I am using EF4 and I have one application where I use DataBase First, which originally created the ObjectContext, and I donwloaded the DbContext generator and generated it.
The thing is, I need the application to be able to get the database SCHEMA from some configuration file, instead of ALWAYS using the “dbo” default.
I was trying to use the “ToTable” method (so I can specify the schema) in the “OnModelCreating” overload method but as this article sais, as I am using DataBase First, that method is not called.
How can I make the schema name configurable?
Is that even possible?
I read this article too, where it says I can combine database first with code first but I can’t see how to do that if I can’t use the "OnModelCreating" method.
Thanks a lot in advance!!!
I don't know about configuring schema. However if you want your db first approach to changed to the code first, just change the string parameter of your DbContext constructor.
Suppose that you have the following DbContext that EF Db first created for you:
public class MyDbContext : DbContext
{
public MyDbContext()
: base("Name=DefaultConnection")
{
}
// DbSets ...
}
change that to the following to start using code first and all magic tools of it (migration, etc.):
public class MyDbContext : DbContext
{
public MyDbContext()
: base("YourDbFileName")
{
}
// DbSets ...
}
It causes that EF creates a new connection string using SQL Express on your local machine in your web.config file with the name YourDbFileName, something just like the early DefaultConnection Db first created.
All you may need to continue your way, is that edit the YourDbFileName ConStr according to your server and other options.
I am learning MVC4 in Visual Studio and I have many questions about it. My first statement about MVC is that MVC's Model doesnt do what I expected. I expect Model to select and return the data rows according to the needs.
But I read many tutorial and they suggest me to let Model return ALL the data from the table and then eliminate the ones I dont need in the controller, then send it to the View.
here is the code from tutorials
MODEL
public class ApartmentContext : DbContext
{
public ApartmentContext() : base("name=ApartmentContext") { }
public DbSet<Apartment> Apartments { get; set; }
}
CONTROLLER
public ActionResult Index()
{
ApartmentContext db = new ApartmentContext();
var apartments = db.Apartments.Where(a => a.no_of_rooms == 5);
return View(apartments);
}
Is this the correct way to apply "where clause" to a select statement? I dont want to select all the data and then eliminate the unwanted rows. This seems weird to me but everybody suggest this, at least the tutorials I read suggest this.
Well which ever tutorial you read that from is wrong (in my opinion). You shouldn't be returning actual entities to your view, you should be returning view models. Here's how I would re-write your example:
public class ApartmentViewModel
{
public int RoomCount { get; set; }
...
}
public ActionResult Index()
{
using (var db = new ApartmentContext())
{
var apartments = from a in db.Apartments
where a.no_of_rooms == 5
select new ApartmentViewModel()
{
RoomCount = a.no_of_rooms
...
};
return View(apartments.ToList());
}
}
Is this the correct way to apply "where clause" to a select statement?
Yes, this way is fine. However, you need to understand what's actually happening when you call Where (and various other LINQ commands) on IQueryable<T>. I assume you are using EF and as such the Where query would not execute immediately (as EF uses delayed execution). So basically you are passing your view a query which has yet to be run and only at the point of where the view attempts to render the data is when the query will run - by which time your ApartmentContext will have been disposed and as a result throw an exception.
db.Apartments.Where(...).ToList();
This causes the query to execute immediately and means your query no longer relys on the context. However, it's still not the correct thing to do in MVC, the example I have provided is considered the recommended approach.
In our project, we will add a Data Access Layer instead of accessing Domain in controller. And return view model instead of Domain.
But your code, you only select the data you need not all the data.
If you open SQL Profiler you'll see that's a select statement with a where condition.
So if it's not a big project I think it's OK.
I can't see these tutorials but are you sure it's loading all the data? It looks like your using entity framework and entity framework uses Lazy laoding. And Lazy loading states:
With lazy loading enabled, related objects are loaded when they are
accessed through a navigation property.
So it might appear that your loading all the data but the data itself is only retrieved from SQL when you access the object itself.
I'm developing an multilingual enterprise web site and I would like to store the localization in database.
I have read the following article which is very good but I personally think that is a an overhead and I can achieve the same much easy:
Extending the ASP.NET 2.0 Resource-Provider Model
I have already setup some ground but I'm not sure if my approach is fine. Basically I have created a service that is registers with DI.
public interface ILocalizedStringProvider
{
string GetLocalizedString(string key);
string GetLocalizedString(string key, string deafultValue);
}
Also i have created a Html helper like this
public static MvcHtmlString LocalizedString(this HtmlHelper helper, string key, string defaultValue)
{
if (string.IsNullOrEmpty(defaultValue)) return new MvcHtmlString("");
if (string.IsNullOrEmpty(key)) return new MvcHtmlString(defaultValue);
ILocalizedStringProvider localizedStringProvider = DependencyResolver.Current.GetService<ILocalizedStringProvider>();
if (localizedStringProvider == null)
{
return MvcHtmlString.Create(defaultValue);
}
string val = localizedStringProvider.GetLocalizedString(key, defaultValue);
if (string.IsNullOrEmpty(val))
{
return MvcHtmlString.Create(defaultValue);
}
return MvcHtmlString.Create(val);
}
Then the helper is simply invoked from the view.
First I want to know if this approach is good and if is not an anti-pattern.
Second my concern is this line:
ILocalizedStringProvider localizedStringProvider = DependencyResolver.Current.GetService<ILocalizedStringProvider>();
Is it maybe better to resolve the service ILocalizedStringProvider in the controller with constructor injection and let the controller populate the ViewBag with the localization's?
Thanks!
You can use my Griffin.MvcContrib project. It contains a ready to use MS SqlServer implementation for storing localization in the database.
Introduction: http://www.codeproject.com/Articles/352583/Localization-in-ASP-NET-MVC-with-Griffin-MvcContri
Administration
There is also an adminstration area which you can use to manage the localizations:
SQL Server setup
https://github.com/jgauffin/griffin.mvccontrib/wiki/SqlServer
Source code
The project is available at github: https://github.com/jgauffin/griffin.mvccontrib
Here is a very good one :
http://west-wind.com/westwind.globalization/
It offers :
DB storage
Resx Import/Export
Strong Type Class generation
it is rapidly added to your projects via Nuget, and you have the Full Source Code.. Awesome stuff
How do I integrate ReportViewer in asp.net MVC project?
I want to add business objects of MVCProject.Model namespace. ReportViewer allows Business objects of DataSet.
Is it possible to choose other data source, like LinqDataSource, or Direct object to LINQ-to-SQL class objects?
What would be the best solution to add reports in an MVC project?
An alternative way to do this would be to generate the report on the reporting server, then stream it to the mvc app as a PDF.
I got an idea that is not tested but may work.
1- Place report viewer control in a standard ASP.Net web form page (e.g. ReportViewer.aspx)
2- Under your MVC, add an iframe that references to this ReportViewer.aspx page
3- Pass parameters to the page using sessions or query strings
Let me know if th is works
It's gonna be tough. First, you need ViewState so you'll need to host the report in a regular WebForms page. This isn't too bad though - WebForms and MVC work fine side-by-side.
The hard part is binding to real IEnumerable objects and not those phoney-baloney ObjectDataSources.
The first step is to build up a report data model. You can do this in code, with queries, whatever, however you want. A structure something like this (but obviously much bigger) is typical:
public class ReportSource
{
public Floogle[] Floogles { get; set; }
}
public class Floogle
{
public Doodad[] Doodads { get; set; }
public string Text { get; set; }
}
public class Doodad
{
public int Number { get; set; }
}
The trick is to use a BindingSource control in your report and set the DataSource property to typeof(ReportSource) - yes, the data source is the type of your report model.
When designing your report you won't get a lot of richness, but you'll be able to do it.
As far as third party reporting solutions go, we've found Telerik's to be the best option.
I've got a small project I threw up on codeplex that is an mvc project with a report.
http://mvctaskmanagement.codeplex.com/
Basically since I do dev on an XP box, my web form had to get pushed to a separate project. Since I have a service layer proj, I stuck it in there.
From there I call my report via a ajax post shooting the params over to the report page, which then passes it down to the same service layer used to generate the preview.
Good luck!