Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

A little resource problem
Baseless
#1 Posted : Friday, July 16, 2010 4:48:36 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
Hi folks

I seem to be having some problems when trying to gather all my text resources in an easy-to-handle manner. The problem is demonstrated below:


This code generates "object not set to an instance"
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using Everest.CmsServices.Models;
using Everest.CmsServices.MvcHelper;
using Everest.CmsServices.Extension.Module;
using Kooboo.Module.Arloesi.MemberControls.Models;

namespace Kooboo.Module.Arloesi.MemberControls.Controllers
{
public class RegisterController : ModuleController
{
public ActionResult Index()
{
Tst test123 = new Tst();
Response.Write(test123.Validate());
return View(new ViewModels.MemberForm(null));
}
}

public class Tst : ModuleController
{
public string Validate()
{
string baba = GetTextResource("test3224", "TEST TEXT");
return baba;
}
}
}



Whlie this code(ofcourse) works fine.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using Everest.CmsServices.Models;
using Everest.CmsServices.MvcHelper;
using Everest.CmsServices.Extension.Module;
using Kooboo.Module.Arloesi.MemberControls.Models;

namespace Kooboo.Module.Arloesi.MemberControls.Controllers
{
public class RegisterController : ModuleController
{
public ActionResult Index()
{
Response.Write(GetTextResource("test3224", "TEST TEXT"));
return View(new ViewModels.MemberForm(null));
}
}
}


Since im trying to lift out all textresources for custom errormessages and such, this causes a bit of a problem. Any good hint on how to get around this? Separate function in the same namespace works fine but desnt solve what im after.
GazNewt
#2 Posted : Friday, July 16, 2010 7:37:26 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 2/2/2010(UTC)
Posts: 122
Location: England
Are you deriving Tst from ModuleController so you can get access to GetTextResource()?

You can get to resource values from CmsContext, you could create your own base class for your controllers where you would put the GetReousrce() function, or you could create a library where you pass in CmsContext

I don't know if this is anythign to do with your problem though, but it doesn't look right to have a utility class derived from ModuleController to me?!?
luiz@wise.com.br
#3 Posted : Friday, July 16, 2010 8:13:01 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 3/4/2010(UTC)
Posts: 157
Location: brazil
It's not a good design at all extend the controller class if you're not using it as a controller, I'm not sure if it will work but you can call initialize method in the controller before calling the validate

maybe a better design option is to create an abstract class that extend modulecontroller and them all of your controller classes extend you base controller class with all your funcionality
Baseless
#4 Posted : Friday, July 16, 2010 10:32:27 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
Luiz / Gaz: Regarding extending the controller i tought that would be subpar / bad practise as well but was a bit uncertain on how to go about it the best way so wanted just to show what im after. My goal was to keep all text resource information for the project in the same place(except the localized labeltexts etc that reside in the views). I tried a couple of things but didnt really work out(Am learning MVC at the same time im learning Koobo so a bit to take in at the same time).
Alternative as i thought of after i posted was perhaps to only store only the string resources(the exception strings etc) and then assemble the ones needed via returned List in the controller to the modelerrors / gettextresources like:

Code:
List<InputError> Errors = arVal.ValidateMember(NewMember);
foreach (var Itm in Errors)
ModelState.AddModelError(Itm.ElementID, GetTextResource(Itm.ResourceID, Itm.ResourceText));


Edit: Think i will use a baseclass / text separation combo, see if that will give me a clean separation, thx for the input!
GazNewt
#5 Posted : Saturday, July 17, 2010 3:17:03 AM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 2/2/2010(UTC)
Posts: 122
Location: England
If you're interested in how I get resources in my modules, I have a separate dll (a base class derived from ModuleController would also be fine) containing a static class :

Code:

public static class Resources
{
    static Resources()
    {
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="oController"></param>
    /// <param name="key"></param>
    /// <param name="defaultValue"></param>
    /// <returns></returns>
    static public string GetResource( Everest.CmsServices.MvcHelper.CmsContext oCmsContext, string key, string defaultValue)
    {
        key = StringExtensions.TryTrim(key);
        IDictionary<string, string> aTextResources =
                UnityManager.Resolve<TextResourceService>().GetTextResources( oCmsContext.Cms_Application.ApplicationName);

        if (aTextResources.ContainsKey(key))
        {
            return aTextResources[key];
        }
        else
        {
            //Add the key, it doesn't exist yet. We'll need it next time
            UnityManager.Resolve<TextResourceService>().AddTextResource(
                                                            oCmsContext.Cms_Application.ApplicationName,
                                                            key,
                                                            defaultValue);
            return defaultValue;
        }
    }
}


If I remember correctly I kind of grabbed this from the Kooboo source and pushed it into my namespace. I wanted the functionality where, if the resource key you are after doesn't exist, it automatically creates it for you with the supplied default
Baseless
#6 Posted : Saturday, July 17, 2010 5:26:14 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
Gaz: Thx, that seems interesting. Am gonna use a baseclass anyway because of other matters but the problem i have with base class i guess will be the same as the example i showed(that is they need to reside in the base class namespace). But your example seems to be able to help me solve the problem in conjunction with some sort of static list so will try that.

Another thought i had was how to be able to create all reasources at installation and then be able to fetch localized versions of the resources at the different region sites without manually having to translate it all when its needed. Import/export as ive seen is only whole applications?
For example if one build a site template and some of the implemented sites want 2 or 3 languages that ive translated earlier i can implement them without translating all module resources by hand each time. Though this is not something ive looked into yet at all, first my plan is to get the module im building now up and running. But collecting all "codebehind/controller/model" resources in one place seems like a good thing to do if i later plan to have different versions of them.
Baseless
#7 Posted : Sunday, July 18, 2010 2:52:50 AM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
Gaz: i built a class based on your code and it seems to work nicely! The way i found to retrieve the cmscontext where with HttpContext.Current.GetCmsContext(), dunno if thats the cleanest way to get it but it works.

Though still thinking a bit if i should like put the resourcestrings in a dictionary/list/ static const class (in wich case i actually dont need anything other then the built in GetTextResource) or i should handle the textresourses completely in an isolated class and just deliver the appropriate strings to the places their needed. ie:

getresource -> string / list ->controller modelerror
or key/defaultvalue strings -> list -> addmodelerror("", gettextresoruce(key, defaultvalue)).

Im after the method creating the least overhead that is. Feels like one got it all served on a platter using resourcefiles ;) with the pros and cons that presents.




GazNewt
#8 Posted : Sunday, July 18, 2010 7:58:52 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 2/2/2010(UTC)
Posts: 122
Location: England
The code I posted calls this Kooboo API function :

Code:
Everest.CmsServices.Services.TestResourceService.GetTextResources(string application);


This function caches an IDictionary<string,string> for you so does that help you with your overhead requirements?

See :

Code:
public IDictionary<string, string> GetTextResources(string application)
{
string cacheKey = string.Format("__TextResource_Application:{0}", application);
IDictionary<string, string> resources = CacheManager.Get(CachedData.Template, cacheKey) as IDictionary<string, string>;
if (resources == null)
{
IEverestCmsDataContext dataContext = EverestCmsEntities.GetDataContext();
var textResourceQuery = dataContext.QueryTextResources(application);

resources = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);

foreach (var item in textResourceQuery)
{
if (!resources.ContainsKey(item.ResourceKey))
{
resources.Add(item.ResourceKey, item.ResourceValue);
}
}

CacheManager.Add(CachedData.Template, cacheKey, resources, CacheItemPriority.Normal, null, CachedData.DefaultExpirations);
}
return resources;
}
Baseless
#9 Posted : Sunday, July 18, 2010 9:41:03 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
Yes but the GetResource code you posted does approx the same as the built in GetTextResource(key, defaulttext), except that GetTextResource only generates object not set to instance when fired outside of controller (as far as ive tested anyhow, modulesettings does the same).

Regarding the last example you posted it takes the kooboo resources into a cache correct? Im not really to worried about the overhead regarding the fetchtimes from kooboo though. What i wanted was:

What i wanted to avoid:

Code:
Controller1
GetTextResource("KEY1", "STRING1");

Controller2
GetTextResource("KEY2", "STRING2");

Controller3
GetTextResource("KEY1", "STRING1");
GetTextResource("KEY2", "STRING2");


What i was after:

Code:
Controller1
GetTextResource(key1, string1);

Controller2
GetTextResource(key2, string2);

Controller3
GetTextResource(key1, string1);
GetTextResource(key2, string2);


Some class
parentfolder = "Setings.";
key1 = parentfolder + "KEY1";
string1 = "STRING1";
key2 = parentfolder + "KEY2";
string2 = "STRING2";



Or that the static class contained the affected resources directly, setting them there. It could be perhaps const like above or dicionary item or other. Though your cached example would be nice to but using that as is would mean i still have to set the properties somehow thus initializing / creating the resources. SO what i was after was to never set static strings in the controllers, the key and defaultvalue in the gettextresource and your getresource functions being suchs strings.
Since my plan is to reuse atleast some of the resources settings and setting the same string values on multiple resource calls seems bad and makes it hard if i where to change values or translate to other language later on for example.

THOUGH with that said i think a cached dictionary containg the static strings seems like a nice option but question is if it where to make any practical difference compared to for example just placing all strings in a class, fetching them when needed.
Baseless
#10 Posted : Sunday, July 18, 2010 9:55:17 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
Though one way of removing the issue would be not to use defaultvalues incode, setting them using a Generate function manually after install. And only have a const string for the parentfolder so its changeable without to much hassle.
Atleast havent seen any functionality to create a list of resources automatically at install.
GazNewt
#11 Posted : Sunday, July 18, 2010 10:42:53 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 2/2/2010(UTC)
Posts: 122
Location: England
You could have a module with a page that generates all the stuff you need, just browse to it once and let it do its work. You could pass the parentfolder in the module parameters
Baseless
#12 Posted : Monday, July 19, 2010 12:15:25 AM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
True, thats one option. Will do some coding and see where it leads ;)
Baseless
#13 Posted : Monday, July 19, 2010 1:25:57 AM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
Btw Gaz: You dont happen to have any samplecode for fetching modulesettings? It seems like ModuleInfo.ModuleSettings[].Value handles like gettextresource, ie cant get it outside controller action(no matter namespaces etc one uses).
Am playing around to find a solution but if you happen to sit on any samplecode for that as well please post, the GetResource worked perfectly.
GazNewt
#14 Posted : Monday, July 19, 2010 2:12:10 AM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 2/2/2010(UTC)
Posts: 122
Location: England
This is how I do it, I have a base class for retrieving module settings :

Code:

public abstract class ConfigBaseClass
{
    private ModuleSettingCollection m_aModuleSettings;
    
    public ConfigBaseClass( ModuleSettingCollection aModuleSettings)
    {
        m_aModuleSettings = aModuleSettings;
    }
    
    public string GetModuleSetting( string sKey)
    {
        return GetModuleSetting( sKey, "");
    }
    
    public string GetModuleSetting( string sKey, string sDefault)
    {
        string sResult = sDefault;
        
        if( m_aModuleSettings != null)
        {
            ModuleSetting oSetting = m_aModuleSettings[sKey];
            if( oSetting != null)
            {
                sResult = oSetting.Value;
            }
        }
        
        return sResult;
    }
}


This is abstract as I inherit it on a per module basis where I add public properties that wrap module parameters specific for that module eg;

Code:

public class Config : ConfigBaseClass
{    
    private string m_sUITemplateConfigName;
    private TimeSpan? m_oCachePeriod;
    private int? m_nPageSize;
    private bool m_bCachePeriod_TriedToGetValue;
    
    public Config( ModuleSettingCollection aModuleSettings) : base( aModuleSettings)
    {
        m_bCachePeriod_TriedToGetValue = false;
        m_oCachePeriod = null;
    }
    
    /// <summary>
    /// This is the filename that is loaded in when it builds the simple admin
    /// interface. 100% required!
    /// </summary>
    public string UITemplateConfigFile
    {
        get
        {
            if( m_sUITemplateConfigName == null)
            {
                m_sUITemplateConfigName = GetModuleSetting( "UITemplateConfigFile", "SimpleAdmin.xml");
            }
            
            return m_sUITemplateConfigName;
        }
    }
    
    public TimeSpan? CachePeriod
    {
        get
        {
            if( m_bCachePeriod_TriedToGetValue == false)
            {
                string sTemp = GetModuleSetting( "CachePeriod");
                
                if( sTemp != null)
                {
                    m_oCachePeriod = GarethElms.Kooboo.Standard.Date.ParseTimeSpan( sTemp);
                }
                
                m_bCachePeriod_TriedToGetValue = true;
            }
            
            return m_oCachePeriod;
        }
    }
    
    /// <summary>
    /// How many items to display in a list of content items. The list
    /// can be with a variety of filters from dates, category or no
    /// filter at all
    /// </summary>
    public int? PageSize
    {
        get
        {
            if( m_nPageSize.HasValue == false)
            {
                m_nPageSize = int.Parse( GetModuleSetting( "PageSize", "10"));
            }
            
            return m_nPageSize;
        }
    }
}


In each module I have a controller base class derived from ModuleController. This base class has a private property :

Code:

public SimpleAdmin.Core.Config m_oUIConfig {get; private set;}


And a public property I can call from my action methods :

Code:

public SimpleAdmin.Core.Config UIConfig
{
    get
    {
        if( m_oUIConfig == null)
        {
            m_oUIConfig = new SimpleAdmin.Core.Config( ModuleInfo.ModuleSettings);
        }

        return m_oUIConfig;
    }
    private set {}
}


Then in my action methods I can just call
Code:
UIConfig.CachePeriod
or
Code:
UIConfig.GetModuleSetting( "name", "default")
or something like that

Baseless
#15 Posted : Monday, July 19, 2010 3:16:44 AM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
Thanks a bunch for everything, will check that out!
Baseless
#16 Posted : Saturday, July 24, 2010 4:40:38 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
I did some coding and ended upp with a scheme similar to yours but added some thiings and with all resurce strings collected in a single dictionary. Everything works very well but one problem still bugs me ;)

Its the scenario where you have a class that you never manually create instances of that class. I happen to have a couple of these wich are used for data annotation(set up in an abstract inherited class for the annotation classes). I know its not recommended using HttpContext, but that way i atleast can get the applicationname = text resources to work.

Though how to get the modulesettings without passing from controller actions still haunts me. Static variables should get me in trouble if trying to change settings at runtime i guess so thats not really god solution either.

SO if anyone has a good suggestion on how to grab the modulesettings(ang perhaps a better cmscontext way that httpcontext) that doesnt require being passed from controller action via constructors etc please let me know. Am checking around in the Kooboo CMS source(ModuleInfo.cs) but dont have any concrete solution yet.
GazNewt
#17 Posted : Saturday, July 24, 2010 4:46:26 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 2/2/2010(UTC)
Posts: 122
Location: England
I have the same problem when I have static classes that act as helpers such as getting text resources from Kooboo. These classes are outside of the module controller so can't access CmsContext.

How about a singleton that is initialised from your base controller? Then all dependent classes outside the module controller can getInstance() of the singleton to access properties normally only accessible from the controller. Or is this obvious and you mean something better than that?!

At the moment I have two or three places where I pass CmsContext along, it feels messy and isn't scalable
Baseless
#18 Posted : Saturday, July 24, 2010 7:17:06 PM(UTC)
Rank: Advanced Member
Groups: Registered

Joined: 6/10/2010(UTC)
Posts: 135
Location: Sweden
I was trying to avoid singleton and statics(except the resource dictionary wich i hold as static), and if it werent for the darn annotation classes i would have gotten away with it ;)
For all repositories etc i just get a single instance of my moduleconfig baseclass and pass it on.
But dont really see any other way out of it atm.
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Powered by YAF 1.9.5.5 | YAF © 2003-2011, Yet Another Forum.NET
This page was generated in 0.281 seconds.