Jang a server-side/client-side view engine for MVC and javascript
PM> Install-Package Jang
Jang was born out of a desire to have a single template that works on both server and client side using any view engine necessary.
For instance an ajax site that polls for a new comment and inserts it into the page without a post back you’ll have to maintain two views
one for the server-side generation of the initial page and one for the client-side rendering with an ajax call.
Jang makes it easier to have the best of both worlds. With a single call you can render the same view on the server, while at the same time make a call
on the client and render the same view with new data.
Example
Here is a sample view that generates a list of users from a model.
//userlist.jazz
< ul>
@for(var i in model.Model) {
@jang.renderView("user", model.Model[i])
}
< /ul>
//user.jazz (this is a child view)
< li>@model.Model.Name< /li>
Server-side Views
Rendering a view on the server side is almost no different from how you render child views in Razor.
@Html.RenderTemplate(viewName, Model)
This can be done almost anywhere you currently call child views.
Client-side Views
There are two ways to render a client-side view.
Direct call
jang.renderView("user", model)
This will return the html of the rendered view which you can then use to insert into the dom.
Making an ajax call with jang.ajax will automatically render the view for you and return the resulting html.
jang.ajax({ url: '/home/user', success: function (result) { $("ul#users").append($(result)); } });
On the server side you need to return a proper response for the view to be rendered. A “JangResult” object has been provided to make this easy.
public ActionResult User() { return new JangResult(new User {Name = "this is a new user "}); }
The JangResult automatically determines the view name based on the action or you can specify a different one yourself.
The goal was to make this seamless and invisible to the consumer.
View Engines
Jang was designed to support additional view engines. Support exists for jsRender, Underscore, Mustache and Jazz. (Jazz is currently still in alpha)
The above sample can be translated:
jsRender
//userlist.jsrender
< ul>
{{#each Model}}
< li>{{=Name}}< /li>
{{/each}}
< /ul>
Underscore
//userlist.underscore
< ul>
<% for(var index = 0; index < Model.length; index++) {%>
<%= jang.renderView("user", Model[index]) %>
<%}%>
< /ul>
//user.underscore (this is a child view)
< li><%= Model.Name %>< /li>
Mustache
//userlist.mustache
< ul>
{{#Model}}
< li>{{Name}}< /li>
{{/Model}}
< /ul>
The source for this project is hosted on Github at https://github.com/Buildstarted/Jang please fork it and add support for more view engines :)
I’ll have a future post detailing how it all works.
- Ben Dornis
Socal Code Camp Post-Mortem
Code Camp is over. I went to a lot of wonderful sessions. A couple of timing issues hit me with the schedule because there were definitely sessions I wanted to attend at the same time as another session I wanted to attend. c’est la vie.
As ~15 of you know I had my first ever speaking engagement on Sunday about Routing in Asp.net. I want to thank all of your for sticking to it until the bitter end. I’m not as flashy as Scott Hanselman. I don’t have the presence of Scott Guthrie. But I gave it my all and it was fun. I’ll definitely do it again.
I realized after the session started that I needed a lot more practice. Nerves got the better of me and basically my brain shut down and forgot everything. I didn’t reference my notes often enough. Alt-tabbed *way* too often. (one viewer mentioned that my scrolling made her dizzy) All in all it was a mess but one that will be refined with more work and a better understanding of the types of questions you attendees asked. Through your questions I was able to see some deficiencies in my presentation that I hope will be fixed next time.
Some of you asked for code. I will post it as soon as I have time to refine it. In it’s current state it doesn’t make for a good download as it’s a huge jumble. I’ll separate my examples out into clear self-contained projects so that each separate concept can be tested and understood on it’s own without any of the other concepts getting in the way.
Another thanks to every who attended and thanks to Code Camp for making it possible.
Ben Dornis
Socal Code Camp this weekend!
Sunday, January 29th 2012 will be my first foray into public speaking. I’ll be speaking at Socal Code Camp at Cal State Fullerton about Routing in Asp.Net.
If you’re attending my session please come back to this post afterward and leave comments. Positive or negative doesn’t matter to me as long as they’re constructive. Anything to help improve my future sessions.
Thanks in advance,
Ben Dornis
Introducing SignalR.EventStream
SignalR.EventStream
Introducing a new favorite Nuget package: SignalR.EventStream.
PM> Install-Package SignalR.EventStream
This is a live feed of the visitors to this site. Leave this page open and watch the live feed. Previous visitors will show up in a few seconds.
SignalR.EventStream
SignalR.EventStream allows users to monitor events happening on the server, live. A single call can be made on the server and propagated to any number of clients. This library leverages the power of [SignalR](https://nuget.org/packages/SignalR) to make the client interface simple.
Born out of a desire to see when new users signed up on csharptube.com/ without refreshing the user list and my familiarity with Jabbr.
What can it be used for?
Some events you might be interested in viewing live.
- User signups
- Error notifications
- Live user mapping (see above)
- User notices such as when badges are awarded
- Notice when customer makes a purchase
- Update a page when a new comment is added
- Update a vote count for rankings
- Clearly the list is endless…
That’s all great but what is SignalR?
SignalR is a library developed by David Fowler and Damian Edwards that allows asynchronous connections in ASP.Net that allows you to build real-time multi-user web applications. This basically means that you can execute server-side code directly from a client or execute javascript on the client directly from the server. It uses the best connection your browser can support. WebSockets and LongPolling with support for more coming soon.
Authorize users to view events
There are two methods for streaming. One is Send(..) which sends an event to the “authorized” general group. The second method is SendTo(..) which sends an Event to a specific group of people.
EventStream.Send
The heart of this is that you should be able to send any data to the client and parse it via json. To enable this I’m using Newtonsoft.Json to convert objects passed into a Json string which is then sent to the client. This allows for a lot of flexibility since the client can now handle anything we want. The event type is determined from the type of object passed in – except for anonymous types. You must pass in a specific event type in order to utilize it. Normal string events are typed as “event”.
public interface IEventStream
{
void Send(string @event);
void Send(string type, object @event); //mainly used for anonymous types
void Send(object @event);
void SendTo(string group, string @event);
void SendTo(string group, object @event);
void SendTo(string group, string type, object @event);
}
I throw an exception on anonymous types without a specified string type. One of the interesting gotcha’s in c# is that there’s no built in way to determine if a type is an anonymous one. Borrowing from another project I helped with, (RazorEngine) I’ve pulled in the IsAnonymousType method.
public static bool IsAnonymousType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return (type.IsClass
&& type.IsSealed
&& type.BaseType == typeof(object)
&& type.Name.StartsWith("<>", StringComparison.Ordinal)
&& type.IsDefined(typeof(CompilerGeneratedAttribute), true));
}
This has been a very reliable way of checking whether or not a particular type is an anonymous type.
Usage
To send an event to the “authorized” group you simply make the following call.
IEventStream EventStream = new EventStream();
EventStream.Send("A simple string message");
You can easily handle this in javascript.
(function() {
var eventStream = new EventStream().connect();
eventStream.eventReceived = function(type, data) {
console.log(data);
});
})();
To send an event to a particular group you simply pass in the group you wish to send it to.
IEventStream EventStream = new EventStream();
EventStream.SendTo("message-group", "A simple string message");
If you just wait on this page all events will be captured and alerted. For more complex data, however.
IEventStream EventStream = new EventStream();
EventStream.Send(new UserSignup {
Username = "Buildstarted",
Realname = "Ben Dornis",
BlogUrl = "buildstarted.com"
});
SignalR.EventStream automatically builds a Json string and passes it to the clients.
(function() {
var eventStream = new EventStream().connect();
eventStream.eventReceived = function(type, data) {
/* Handle this more complex object */
});
})();
Page specific sends
To make things easier to update pages I’ve added a PageStream() type in the eventStream.js. This uses the current pathname of the url as the group. You can then send events to any client currently viewing that page. This makes it really easy to add new comments or modify the rankings for a page.
(function() {
var pageStream = new PageStream().connect();
pageStream.eventReceived = function(type, data) {
//update the vote count!
};
});
var path = new UrlHelper(ControllerContext.RequestContext).Action("index");
new EventStream().SendTo(path, "this is a page update");
I’m looking at how to create a path from the current request easier than that and externally to a Controller. (update forthcoming).
You can use any simple javascript templating engine that handles json to automatically build an html object and insert it into the dom.
You can find the source for SignalR.EventStream on Github.
–”[SignalR.EventStream] makes me want to look at SignalR”
-Ben Dornis
What are your favorite Nuget MVC packages
What are your favorite MVC packages available on Nuget? Why?
Here are the most common ones I end up installing in a new MVC Application: