0

I'm having some problem to implement a clonable version of the ControllerContext. I need this because i'm trying to cache it and access it later in a part of my system that can't access this information and i can't pass it as a parameter. This is what i have achieved:

public class ControllerContextClonable : ControllerContext, ICloneable
{
    public object Clone()
    {
        var cloneContext = (ControllerContext)MemberwiseClone();

        return cloneContext;
    }

    public static List<ControllerContextClonable> ToList( ControllerContextClonable context )
    {
        return new List<ControllerContextClonable>{ context };
    }
}

The problem is: When i'm caching it, i have the ControllerContext but i need to pass to my caching method a ControllerContextClonable object. How can i convert my ControllerContext to ControllerContextClonable ? This is how i'm trying to pass it and the caching methods:

//If i try to call my method with the safe convertion i get a null object
CacheMethods.SetContextCache( context as ControllerContextClonable );

public static void SetContextCache( ControllerContextClonable context, string cacheKey = "SiteContext" )
{
    CacheList<ControllerContextClonable>.RemoveCache( cacheKey );
    CacheList<ControllerContextClonable>.Add( new List<ControllerContextClonable> { context } );
    CacheList<ControllerContextClonable>.CacheIt( cacheKey );
}

public static ControllerContextClonable GetCachedContext( string cacheKey = "SiteContext" )
{
    CacheList<ControllerContextClonable>.LoadCached( cacheKey );

    if( CacheList<ControllerContextClonable>.LoadCached( cacheKey ) )
    {
        return CacheList<ControllerContextClonable>.DataList.FirstOrDefault();
    }

    return null;
}

How can i correctly convert the executing ControllerContext to my ControllerContextClonable class to be used on the cache ? Also if i'm doing this wrong could anyone point me the right way ?

EDIT:

I'm going to explain my workaround: I'm creating a template parsing system where it will parse a template using a tag system, in this tag the user will provide the ViewModel class and the template View he wishes to use.

Having that i will instantiate this ViewModel using this code to do it. This code doesn't let me pass a controllercontext as a parameter, i tried to modify it to accept the parameter but it would give me an Common language runtime detected an invalid program error.

Now the problem, on this certain case i have a ViewModel that needs to fetch information that was saved on a ViewBag using my Filter. The only solution i could think of was cache the context and access it but i'm failing on the convertion part. Could i solve this any other way ? What i need is to access the Context inside some methods that are called by my ViewModel constructor.

This is the ViewModel:

public class LanguageTestViewModel
{
    //Properties

    public LanguageTestViewModel() { Initialize( "", "", 0 ); }

    public LanguageTestViewModel( string where, string order, int take ) { Initialize( where, order, take ); }

    private void Initialize( string where, string order, int take )
    {
        var Context = CacheMethods.GetCachedContext();
        var EList   = HelperMethods.CreateSelectListItem( "SELECT A STATE", Context );
        var States  = CacheMethods.GetStatesForm( Context );

        //Do stuff
    }
}

EDIT 2

I have to change my storage method since i'm using HttpRuntime.Cache, which is a shared storage and i can't storage context information on that can change based on user, device, location, etc.. Said that i need this information on a per-user storage. Any ideas ?

Community
  • 1
  • 1
Ariel
  • 911
  • 1
  • 15
  • 40
  • 3
    I suspect your actual problem is that you are trying to cache this object in the first place. Perhaps there is a better solution if you would describe the "later part of your application" that is using this context and why you can't pass it directly. If this is a cross-cutting concern, a better approach would be to use an [MVC filter](https://msdn.microsoft.com/en-us/library/gg416513(VS.98).aspx), which is context-aware, rather than trying to stuff the context into a part of the application where it doesn't belong. – NightOwl888 Mar 18 '16 at 15:49
  • @NightOwl888, i have added more information about the system – Ariel Mar 18 '16 at 16:14

1 Answers1

1

I have a solution for you. Clone the controller instance and then you have access to the objects.Notice I am using HomeController that implements IControllerContextClonable. This example is the simplest solution. But it works. Eg.

using System.Collections.Generic;
using System.Web.Mvc;

namespace WebApplication1.Controllers
{
    public class HomeController : Controller, IControllerContextClonable
    {
        public ActionResult Index()
        {
            var controller = (HomeController) this.MemberwiseClone();
            var list = ToList(controller);

            return View();
        }

        public List<IControllerContextClonable> ToList(IControllerContextClonable context)
        {

            return new List<IControllerContextClonable> { context};
        }
    }    

    public interface IControllerContextClonable
    {
        List<IControllerContextClonable> ToList(IControllerContextClonable context);    
    }
}

Output. ControllerContext instance is nicely hydrated.

enter image description here

The SetContextCache method will have the signature as below. Notice the parameter type is IControllerContextClonable. This way SetContextCachemethod will accept any type that implements IControllerContextClonable

public static void SetContextCache(IControllerContextClonable context, string cacheKey = "SiteContext" )
{
    CacheList<IControllerContextClonable>.RemoveCache( cacheKey );
    CacheList<IControllerContextClonable>.Add( new List<IControllerContextClonable> { context} );
    CacheList<IControllerContextClonable>.CacheIt( cacheKey );
}

You can then pass any instance of a type(a class) that implements IControllerContextClonable as below.This is valid because HomeController implements IControllerContextClonable. You have access to the object and you can manipulate it as you desire.

e.g.

  var homeController = new HomeController();

  CacheMethods.SetContextCache(homeController);
Julius Depulla
  • 1,493
  • 1
  • 12
  • 27
  • Thank you for this but i just realized that i can't work with my `CacheMethods` since they use `HttpRuntime,Cache`, which is a shared information and i need a `per-user storage`, like sessions and cookies, for this kind of information. – Ariel Mar 21 '16 at 18:14
  • Yes, for that purpose, you would need to use unique user sessions or cookies – Julius Depulla Mar 21 '16 at 20:35
  • I accepted your answer as correct since you solved my cloning problem. I managed to make the ControllerContext work as a parameter. – Ariel Mar 22 '16 at 12:25
  • 1
    Yes, you can also make the ControllerContext as your parameter. Glad you are happy – Julius Depulla Mar 22 '16 at 15:39