Feature: Conversational session

Topics: ASP.NET MVC
Feb 22, 2013 at 5:41 PM
Edited Feb 22, 2013 at 6:09 PM
I would like to implement a new feature for asp.net mvc called "conversational session".
What is a conversational session? For example, you have a edit page and you want to display this page multiple times but with different data. If you store some data in the session, the session data will be overridden when opening the edit page multiple times. You can use a conversation for a specific "process" and after the process finishes the data will cleared. My idea was to handle this via attributes (i.e. one attribute on a action which starts a conversation.. or a attribute which clears the conversation etc.)

So asp.net mvc... team. What do you think? Can I start with the implementation? :)

I created a suggestion: http://aspnet.uservoice.com/forums/41199-general-asp-net/suggestions/3681333-conversational-session-running-same-views-in-mul
Coordinator
Feb 26, 2013 at 4:30 PM
Thank you for this suggestion and your interest in contributing to ASP.NET MVC.

First I think we need to get a better understanding of the scenario you have a mind. Could you please give as a concrete example of how a conversational session would be used? Are there any examples of applications that use this design pattern?

Also, is this something that needs to live in the core MVC runtime, or is it something that can be done in a purely additive fashion?

Thanks again and we look forward to working with you.
Feb 26, 2013 at 5:51 PM
Hi danroth27. First of all, thank you for reviewing my feature request!

Answer question 1:
For example, you create an webapp where you have a list of entities and a edit/create page. And the user wants to edit multiple entities at the same time. (Multiple browser windows/tabs)
If you save the current entity which was selected for editing in the session, the session value will be overriden when the user opens a second/third... entity in another window/tab. That means, you can edit only on (This is an example of an simple scenario. I know, it's possible to solve this Scenario without sessions. But if the edit window is much bigger with multiple sites it can make sense to store the data in the sesion until the users saves the chnges.)

Answer question 2:
It's a good question. First I wanted to create a Little NuGet package for this. But an conversational session must always have an identifier. This identfier must be added to every generated link (@Html.ActionLink(...)) or form action attribute. It can be done be the developer, but it's nicer when the MVC Framework adds the identifier param on it's own (when it's needed).

We can't know how your end-users are working with our web applications. Advanced users may use multiple tabs/windows. (As explained in answer 1). I think, it's a common problem.

Benefits with conversational session:
  • In case when data is stored in the session and must not be changed by another window/tab.
  • In every situation where you may have like a "process". (Multiple sites for a specific use case.) At the end of the use case the conversational session can be cleared and we can be sure
    that we have cleared all use case related data (AND only the related data).
How I plan to implement it:
I forked the ASP.NET MVC source code and did a little POC.
This is how it could work. (Basic example)
[Conversation]
public class HomeController : Controller
{ 
public ActionResult Index()
    {
        if (this.Conversation["abc"] == null)
            this.Conversation["abc"] = "test";
        return View();
    }

    public ActionResult SiteTwo()
    {
        var conv = this.Conversation["abc"]; // conv is not empty/null
        return View();
    }

    [Conversation(End = true)]
    public ActionResult End()
    {
        var conv = this.Conversation["abc"]; // Conv is not empty/null BUT after the execution of this action the conversation will be cleared (check attribute)
        return View();
    }
}
The this.Conversation property stores the data in the this.Session property under a specific key-nameing. (It would be cool to handle everything over this.Session. But for this, we need to create a new class which derives from HttpSessionStateBase. I think that has a too big inpact on the framework + exists web applications.)
In this basic example you don't see all features. I don't have the complete feature list yet.
But for example, it must be possible to define the scope of the conversation. The example above is shows a controller-scoped conversation. But a scope can be over multiple controllers.
--> [Conversation(Scope="Ordering")] Just an example.

Developer support:
  • By default, when setting up an conversation everything should work by itself. The developer doesn't have to take care about the links generated in the view.
  • Exception: If the view has custom links or ajax calls, then it should be possible to access the current conversation identifier over the view engine. So that the developer can attach the identifier in the custom links.
What does it mean for MVC?
  • Conversational session doesn't have a big impact on the framework. The ConversationAttribute is a filter. That means, only when the developer works with conversations the conversation-logic will be executed. (Like OutputCache for example)
  • The html link/form generator must be modified. I did it already in my POC. I solved it with 2-5 lines of code.
That should be enough for now :)
Mar 7, 2013 at 7:22 AM
Already decided? :)
Coordinator
Mar 8, 2013 at 1:41 AM
Hi there,

As a general rule, features that we put within the MVC framework are the ones that we feel have the broadest appeal to a wide range of customers and scenarios. While the feature of "conversational sessions" does sound cool, we're not sure it has that broad appeal - it's not something we've heard discussed before in terms of an application's requirements.

Perhaps part of the reason that it hasn't yet been asked for is that in general, using session state for per-request data is not recommended, as it goes against one of the core tenets of HTTP, which is that it is a stateless protocol. That is, HTTP is designed around an assumption that the web server doesn't "remember" what the client was doing in a previous request. When we've heard of people trying to implement similar scenarios, the "ID" of the entity being edited will be in the URL (either in the path or in the query string), and the content of the entity being edited will either be in a database or in the form's POST data. In a multi-tab browser scenario this allows each tab to function completely independently of one another because each tab has its own state.

The session-based implementation you describe sound like a good candidate for a standalone NuGet package. If there's a feature change in MVC that might make it easier for you to implement that NuGet package, we should certainly discuss what changes it might involve.

Thanks,
Eilon
Mar 8, 2013 at 6:51 AM
Hi

Thanks eilontop! I agree with you.
I wouldn't use conversational sessions for simple scenarios like editing an entity too.
I'll create a Nuget package for this. The core logic is placed in a ActionFilter attribute and can be placed easily in a standalone library.

But I still to do some things in the MVC core. (If there is an option to do this outside of the core, please let me know!!) :)

1) Adding the conversation key:

To ensure that all links have the conversation key in the querystring, I added following code to the RouteValuesHelpers class.
if (implicitRouteValues.ContainsKey(ConversationContext.ParameterName))
{
    if (mergedRouteValues == null)
    {
        mergedRouteValues = new RouteValueDictionary();
    }
         mergedRouteValues.Add(ConversationContext.ParameterName, implicitRouteValues[ConversationContext.ParameterName]);
}
(The conversation logic adds the conversation key in the AfterActionExecuting... function to the RouteData object.)


2) Developer support:

As already mentioned in the previous post. In the view, the developer must have access to the current conversation key.
For example: If they create links without @html.*** Something like @anyobject.ConversationKey
Mar 9, 2013 at 2:57 PM
Oh I forgot. In my POC the conversation object can be access in the controller object. -> (this.Conversation ...) This won't be possible when the code is outside of the core. (Maybe only with extension methods.)