Sunday, December 19, 2010

Render ASP.MVC Partial Views (*.ascx) to a String

It seems like every ASP.Net MVC project I work on requires me to do this, so I thought I would post it.

A particularly useful application of this technique is passing HTML from the server to the browser using JSON requests (AJAX).

Here is the code:



public static string RenderPartialToString(string partialViewPath, ViewDataDictionary viewData, ViewContext viewContext)

{

    ViewPage vp = new ViewPage();

    vp.ViewData = viewData;

    vp.ViewContext = viewContext;

    Control control = vp.LoadControl(partialViewPath);

    vp.Controls.Add(control);

    StringBuilder sb = new StringBuilder();

    using (StringWriter sw = new StringWriter(sb))

    {

        using (HtmlTextWriter tw = new HtmlTextWriter(sw))

        {

            vp.RenderControl(tw);

        }

    }

    return sb.ToString();

}




The usage is as follows:
public JsonResult RenderVacationList(int id)
        {
ViewData.Model = //Some model object from your data store
string v = Helper.RenderPartialToString("/Views/ControllerName/PartialViewToRender.ascx", ViewData, new ViewContext());
            return new JsonResult()
            {
                Data = new {
                    view = v
                }
                
            };
        }
You can then call this Action method from your javascript and insert the resulting HTML into the page on the fly! Pretty slick..

As always, leave helpful comments/questions below, Thanks!

Setting up SOLR under Apache Tomcat 6 in Windows 7

There are other resources out there with this information, but each of them seem to be missing some minor detail or step, so here it is in its complete glory.

This post assumes a fresh windows installation (no other software installed).

There are three things to download:
1) J2SE (Java 2 Standard Edition JRE)  (click the "Download JRE" button)
2) Apache Tomcat 6 (under "Binary Distributions" click "32-bit/64-bit Windows Service Installer")
3) SOLR (Click on the "Suggested Mirror" link, select the folder for the most recent version, then download the .zip file)


4) Install J2SE.
This is a no-brainer. 

5) Install Tomcat.
 Using the MSI installer file, this is very straightforward.
Notes:
- When you start the installer, check in ALL the boxes for the different components to install. (if you don't want them you can remove the manually later)
- Since you installed J2SE first, the path to the JRE will be pre-populated in one of the installer's dialogs. If it NOT pre-populated, simply find the JRE ("C:\Program Files\Java\jre6" on my machine) and copy/paste its path into the Tomcat installer dialog's field.
- I left the Tomcat username/password fields blank. This isn't an issue if you have your firewall setup correctly (outside the scope of this document).
- At the end of the installation, CHECK the option to start Tomcat when finished.

6) Install SOLR.
 When I create a new development project (in Visual Studio for example), I keep all associated files/tools/applications in the project's folder, so in my case I extracted the SOLR folder to my project's folder. In case you didn't realize.. extracting SOLR --is-- the installation. .. now for the configuration.

7) Copy "solr.war" (or similarly named file which may contain version numbers)
from the extracted path:
"...\apache-solr-1.4.1\dist\solr.war"
to
"C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\"
or the equivalent path on your machine.

If Tomcat is running (which, if you followed this guide exactly, it should be), you will see another folder appear in "webapps" called "solr" after a few seconds.

8) Add SOLR to Tomcat.
 When you installed tomcat, you chose to install all components including a handy little Tomcat Monitoring tool located in your system tray.


 Double click this icon and go to the "Java" tab.


Under "Java Options" add the following line:
"-Dsolr.solr.home=.../solr/"
where ... is the path to your extracted SOLR "installation". Note that this folder is the one that contains the directories "bin" and "conf".

9) Restart Tomcat service.
Now, Click the "General" tab
- Change "Startup type" to "automatic" (tomcat will start with your computer, if you don't choose this, you will need to manually start it each time your system starts).
- Click "stop"
- Click "start"

Note: This can also be done in service.msc (start -> run-> "service.msc", press enter).

This will restart the Tomcat Service running on your machine.

10) Verifying configuration.

Now, navigate to http://localhost:8080/solr/

If you see a "Welcome to SOLR!" message, then everything worked. If you get an error page (gray background with white text) then look at the first few lines and try to figure it out. In my experience, the most likely problem is that you got one of the paths wrong (particularly the "-Dsolr.solr.home=.../solr/" path).

Note that after you change any of the paths, or move files around, you need to restart Tomcat (can do it as demonstrated above)

Leave comments/corrections/useful suggestions below!
Thanks!

Tuesday, December 14, 2010

Storing POCO Properties in SQL server using XML under ASP.NET MVC

This technique allows you to easily expand the types of information your database holds without altering the database and with only minimal code additions. In fact, once everything is set up, to start persisting a new property to the database means simply adding that property to the POCO.

Create your Database
The only special thing that happens here is that each table that you want to store XML data in will need a column to store the XML string for each record. 

An example table might look like this:

CREATE TABLE Employee
(
EmployeeID INT NOT NULL AUTOINCREMENT PRIMARY KEY,
FirstName VARCHAR(50) NOT NULL,
LastName VARCHAR(50) NOT NULL,
XMLProperties XML
);


Notice the 4th column: "XMLProperties" and notice the datatype "XML".

Anything extra that we want to store for an Employee object will be stored in this XMLProperties field. The management of this XML data will all happen in code. That's all there is to it for the database.

Create your objects
The first step is to create your POCO objects. I will use the LINQ-to-SQL tool in VS to automatically generate my objects. 

The LINQ-to-SQL tool generates partial classes (a class for each database table). 
We will take advantage of this and create supplementary partial classes to add those extra properties we wish to store in XML.

Add Properties to be stored as XML
Your POCO's will have properties for the columns of your associated SQL table in the generated partial classes. Lets make our own supplemental partial classes and add our extra properties that will be persisted to XML:

[DataContract(Name = "Employee", Namespace = "http://www.contoso.com")]
public partial class Employee
{

[DataMember(Name = "DOB")]
public DateTime DOB { get; set;}


[DataMember(Name = "Telephone")]
public String Telephone { get; set;}

}

Notice the two attributes we are using here [DataContract] and [DataMember][DataContract] specifies that the class can be used by .NET's DataContractSerializer, and [DataMember] specifies which properties will be serialized. 

Have some way of fetching them and re populating the POCO
Now comes the tricky part, getting the data in and out seamlessly. While there may be more refined methods of doing this, my solution consists of 2 parts:


2) A static "Adapter" utility class to serialize and deserialize the objects to and from XML.

I plan on writing my own post on custom model binding in the future. If you are not familiar with the subject, see the link above. 

The Adapter Class (Psudo code)

public static class XMLAdapter
{

public static LoadXMLProperties(T Model)
{

foreach(Property p in T.GetProperties())
{

 var temp = Deserialize(Model.XMLProperties);
 //use .NET's reflection framework to get and set the properties
 if(p is a "datamember property")
 {
   Model.p.value = temp.p.value;
 }

}

}

public static SaveXMLProperties(T Model)
{
//only the properties with the [DataMember] attribute will be serialized.
Model.XMLProperties = Serialize(Model);

}

}


In our custom model binder's Bind() method, we will call our SaveXMLProperties(T Model) method on the incoming model. This will take all of our XML backed properties and save them as an XML string in the XMLProperties field of our POCO. Now, when the POCO is persisted, its XML Backed properties will be saved as well.

To repopulate these XML Backed properties into the POCO (when fetching them from the database), we can call the LoadXMLProperties(T Model) on the object in our code wherever it is loaded from the database (such as in the controller).


I plan to revisit this topic later in greater detail.

Hopefully you found this post helpful, if for nothing else than to push you in the right direction.

Post your questions and comments below! Thanks.