Maybe Partial?

S

shapper

Hello,

I have a class named CultureAttribute which is used as follows:

[Culture(CookieName = "Culture", Cultures = "en-US,pt-PT",
DefaultCulture = "pt-PT")]
public class BaseController : Controller {
}

The problem is that I would like to use the Culture attribute as
follows:

[Culture(CookieName = Config.Culture, Cultures = Config.Cultures,
DefaultCulture = Config.DefaultCulture)]
public class BaseController : Controller {
}

However this is not allowed. I don't want to access Config properties
directly from CultureAttribute Class because I would like to have this
class in a library which is common to all projects.

My idea is maybe to be able to use something like:
[Culture]
public class BaseController : Controller {
}

So when a property value is not defined I could get use default value
from the Config.
So I would maybe ??? make my CultureAttribute partial and on each
project I would create a partial class of CultureAttribute and for
each property I would check if it is null and if true get the default
values from Config.

Does this make sense?

What is the correct way to do this?

My entire CultureAttribute class code is as follows:

public class CultureAttribute : FilterAttribute, IActionFilter {

public String Cultures { get; set; }
public String CookieName { get; set; }
public String DefaultCulture { get; set; }

public void OnActionExecuting(ActionExecutingContext
filterContext) {

String code = SetCulture(filterContext, CookieName,
Cultures.Split(), DefaultCulture);

if (String.IsNullOrEmpty(code)) return;

HttpContext.Current.Response.Cookies.Add(
new HttpCookie(CookieName, code) {
HttpOnly = true,
Expires = DateTime.Now.AddYears(100)
}
);
filterContext.HttpContext.Session[CookieName] = code;

CultureInfo culture = new CultureInfo(code);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;

} // OnActionExecuting

public void OnActionExecuted(ActionExecutedContext filterContext)
{
} // OnActionExecuted

private static String SetCulture(ActionExecutingContext
filterContext, String cookieName, IList<String> cultures, String
defaultCulture) {

String cookieValue = GetCookieCulture(filterContext, cultures,
cookieName);

// Check cookie culture
if (String.IsNullOrEmpty(cookieValue)) {
String sessionValue = GetSessionCulture(filterContext,
cultures, cookieName);

// Check session culture
if (String.IsNullOrEmpty(sessionValue)) {
String browserCulture = GetBrowserCulture(filterContext,
cultures);

return String.IsNullOrEmpty(browserCulture) ?
defaultCulture : browserCulture;

}
return sessionValue;
}
return cookieValue;

} // SetCulture

private static String GetCookieCulture(ActionExecutingContext
filterContext, ICollection<String> cultures, String cookieName) {

// Get language in culture
HttpCookie userCookie =
filterContext.RequestContext.HttpContext.Request.Cookies[cookieName];

// Check cookie
if (userCookie != null) {
if (!String.IsNullOrEmpty(userCookie.Value)) {
if (cultures.Contains(userCookie.Value))
return userCookie.Value;
else
return String.Empty;
}
return String.Empty;
}
return String.Empty;

} // GetCookieCulture

private static String GetSessionCulture(ActionExecutingContext
filterContext, ICollection<String> cultures, String cookieName) {

// Check session
if (filterContext.RequestContext.HttpContext.Session
[cookieName] != null) {
String sessionCulture =
filterContext.RequestContext.HttpContext.Session[cookieName].ToString
();
if (!String.IsNullOrEmpty(sessionCulture))
return cultures.Contains(sessionCulture) ? sessionCulture :
String.Empty;
else
return String.Empty;
}
return String.Empty;

} // GetSessionCulture

private static String GetBrowserCulture(ActionExecutingContext
filterContext, IEnumerable<String> cultures) {

// Get languages from browser
IList<String> browserLanguages =
filterContext.RequestContext.HttpContext.Request.UserLanguages;

// Check browser languages
foreach (String bl in browserLanguages) {
foreach (String c in cultures) {
if (c != bl)
continue;
return c;
}
}
return String.Empty;

} // GetBrowserCulture

} // CultureAttribute

Thank You,
Miguel
 
S

shapper

Let me explain in a simpler way. I have a class:

public class CultureAttribute : FilterAttribute, IActionFilter {

public String Cultures { get; set; }
public String CookieName { get; set; }
public String DefaultCulture { get; set; }

// More code
}

And I want to create another class (Maybe a partial) so that when a
property is not defined its value should be taken from:
Config.Cultures, Config.CookieName or Config.DefaultCulture.

Basically that's it.

Thank You,
Miguel
 
P

Peter Duniho

shapper said:
Let me explain in a simpler way. I have a class:

public class CultureAttribute : FilterAttribute, IActionFilter {

public String Cultures { get; set; }
public String CookieName { get; set; }
public String DefaultCulture { get; set; }

// More code
}

And I want to create another class (Maybe a partial) so that when a
property is not defined its value should be taken from:
Config.Cultures, Config.CookieName or Config.DefaultCulture.

Basically that's it.

Are you sure that's it? Your previous post seemed to indicate that you
didn't want the CultureAttribute class to actually directly reference
your Config class/instance (whatever it is...as usual, without a
concise-but-complete code example, we don't really know for sure what
"Config" actually means in this context).

It's not clear to me where you're suggesting "partial" comes into this.
Are you suggesting that the CultureAttribute class would reference
some undefined member (method or property), that is then declared in the
other part of the "partial" class implemented in each project that uses
CultureAttribute? That would work only if you are recompiling
CultureAttribute for every project that uses it. I'm not convinced
that's a very maintainable, useful way to approach the problem.

Unfortunately, without a concise-but-complete code example, there's a
lot of inferences that have to be made just to understand the question.
After all, we don't know in what context this CultureAttribute is
used, at which point the various properties need to be initialized, or
have a way of returning a valid value, what "Config" is, etc.

But, one possibility would be to require client assemblies to declare a
type or type member of a certain name and use reflection to find it (you
might call that "Config"), or for client assemblies to register some
kind of proxy that implements a particular interface (maybe a factory,
or maybe just a data retrieval API).

Or it could be that neither of those suggestions make any sense at all.
Without a concise-but-complete code example showing exactly what
you're trying to do, there's a huge amount of guesswork in trying to
figure out what a useful answer might look like.

Pete
 
S

shapper

Are you sure that's it?  Your previous post seemed to indicate that you
didn't want the CultureAttribute class to actually directly reference
your Config class/instance (whatever it is...as usual, without a
concise-but-complete code example, we don't really know for sure what
"Config" actually means in this context).

It's not clear to me where you're suggesting "partial" comes into this.
  Are you suggesting that the CultureAttribute class would reference
some undefined member (method or property), that is then declared in the
other part of the "partial" class implemented in each project that uses
CultureAttribute?  That would work only if you are recompiling
CultureAttribute for every project that uses it.  I'm not convinced
that's a very maintainable, useful way to approach the problem.

Unfortunately, without a concise-but-complete code example, there's a
lot of inferences that have to be made just to understand the question.
  After all, we don't know in what context this CultureAttribute is
used, at which point the various properties need to be initialized, or
have a way of returning a valid value, what "Config" is, etc.

But, one possibility would be to require client assemblies to declare a
type or type member of a certain name and use reflection to find it (you
might call that "Config"), or for client assemblies to register some
kind of proxy that implements a particular interface (maybe a factory,
or maybe just a data retrieval API).

Or it could be that neither of those suggestions make any sense at all.
  Without a concise-but-complete code example showing exactly what
you're trying to do, there's a huge amount of guesswork in trying to
figure out what a useful answer might look like.

Pete

Hi Pete,

Let me try to explain it better what I am trying to do:

I have an assembly, Infrastructure.dll, which I use in all projects.
On this assembly I have a class: CultureAttribute

This Attribute is used as follows:
[Culture(CookieName = "Culture", Cultures = "en-US,pt-PT")]
public class BaseController : Controller {}

The problem is that I can't use it as follows:
[Culture(CookieName = Config.Culture, Cultures = Config.Cultures)]
public class BaseController : Controller {}

Config is just a class I have on each project that gets values from
Web.Config / App.Config.
So I want to be able to define the CookieName and Cultures not in the
code but in the Web.Config / App.Config.

My idea, not sure if it is the best, is the following:
- On each project have a class that would be based on
"CultureAttribute" but would allow to define the properties from
Config.
- Even better would be be able to use it:

[MyProjectCulture(CookieName = "Culture", Cultures = "en-US,pt-PT")]
public class BaseController : Controller {}

So in this case Config wouldn't be used because the properties are
already set.

OR

[MyProjectCulture(CookieName = "Culture")]
public class BaseController : Controller {}

In this case Cultures was not defined.
So it would use the value of Config.Cultures.


Maybe I could have the class CultureAttribute with overriden
properties and then a class on each project named
MyProjectCultureAttribute that would inherit CultureAttribute but
would check when a property is not defined to get the value from
Config. ... ?

This is just another idea (like the partial one) ... I really don't
know how should I do this.

If you have any question please let me know.

Thank You,
Miguel
 
P

Peter Duniho

shapper said:
Let me try to explain it better what I am trying to do:

I have an assembly, Infrastructure.dll, which I use in all projects.
On this assembly I have a class: CultureAttribute

I figured that out already.
This Attribute is used as follows:
[Culture(CookieName = "Culture", Cultures = "en-US,pt-PT")]
public class BaseController : Controller {}

That much was in your original post.
The problem is that I can't use it as follows:
[Culture(CookieName = Config.Culture, Cultures = Config.Cultures)]
public class BaseController : Controller {}

By which I assume you mean that "Config.Culture" is not a compile-time
constant. I figured that out from the original post too.
Config is just a class I have on each project that gets values from
Web.Config / App.Config.

Okay. Not much new information there, but it at least confirms my
suspicions.
So I want to be able to define the CookieName and Cultures not in the
code but in the Web.Config / App.Config.

How does that help you at compile time? Are you comfortable with a code
attribute that could theoretically vary in semantics at run-time? I
think it would work, but it seems a little fragile to me.
My idea, not sure if it is the best, is the following:
- On each project have a class that would be based on
"CultureAttribute" but would allow to define the properties from
Config.
- Even better would be be able to use it:

[MyProjectCulture(CookieName = "Culture", Cultures = "en-US,pt-PT")]
public class BaseController : Controller {}

So in this case Config wouldn't be used because the properties are
already set.

OR

[MyProjectCulture(CookieName = "Culture")]
public class BaseController : Controller {}

In this case Cultures was not defined.
So it would use the value of Config.Cultures.

Yes, you could do that. But then what of code in the Infrastructure.dll
or other external assemblies that want to use ProjectCulture, but depend
on your main project's settings? Or do you not care about that?
Maybe I could have the class CultureAttribute with overriden
properties and then a class on each project named
MyProjectCultureAttribute that would inherit CultureAttribute but
would check when a property is not defined to get the value from
Config. ... ?

Isn't that basically the same as the above suggestion? After all,
overrides only have an effect when you actually have an instance of the
class doing the overriding, which you can only have if you use the
project-specific type name, not the ProjectCultureAttribute type.
This is just another idea (like the partial one) ... I really don't
know how should I do this.

Well, I think the simplest way, assuming this is otherwise a wise thing
to do, would be to have each project somehow initialize the
ProjectCultureAttribute class with the necessary defaults, based on the
Config values. Then ProjectCultureAttribute doesn't have to know
anything at all about the project itself.

Pete
 
S

shapper

shapper said:
Let me try to explain it better what I am trying to do:
I have an assembly, Infrastructure.dll, which I use in all projects.
On this assembly I have a class: CultureAttribute

I figured that out already.
This Attribute is used as follows:
[Culture(CookieName = "Culture", Cultures = "en-US,pt-PT")]
public class BaseController : Controller {}

That much was in your original post.
The problem is that I can't use it as follows:
[Culture(CookieName = Config.Culture, Cultures = Config.Cultures)]
public class BaseController : Controller {}

By which I assume you mean that "Config.Culture" is not a compile-time
constant.  I figured that out from the original post too.
Config is just a class I have on each project that gets values from
Web.Config / App.Config.

Okay.  Not much new information there, but it at least confirms my
suspicions.
So I want to be able to define the CookieName and Cultures not in the
code but in the Web.Config / App.Config.

How does that help you at compile time?  Are you comfortable with a code
attribute that could theoretically vary in semantics at run-time?  I
think it would work, but it seems a little fragile to me.

I have two properties that maybe I would need to change without
recompiling:
DefaultCulture
CookieName

Usually, even in Asp.Net Web.Config is usual to define the cookie
names and default culture in the Web.config.
I would like my attribute to do the same.

I would be fragile?
I mean, I can change the CookieName or CookiePath for example in the
Web.Config and the application would start using those new values.
A lot of other definitions can be change in Web.Config of Asp.Net
applications like ConnectionString, AuthenticationCookieName, etc.

Probably I misunderstood you.

My idea, not sure if it is the best, is the following:
- On each project have a class that would be based on
"CultureAttribute" but would allow to define the properties from
Config.
- Even better would be be able to use it:
  [MyProjectCulture(CookieName = "Culture", Cultures = "en-US,pt-PT")]
  public class BaseController : Controller {}
  So in this case Config wouldn't be used because the properties are
already set.
  [MyProjectCulture(CookieName = "Culture")]
  public class BaseController : Controller {}
  In this case Cultures was not defined.
  So it would use the value of Config.Cultures.

Yes, you could do that.  But then what of code in the Infrastructure.dll
or other external assemblies that want to use ProjectCulture, but depend
on your main project's settings?  Or do you not care about that?

I am not sure that I am following you but:
1. The InfrastructureCultureAttribute should only contain the process
of setting the culture.
The process on that code is the same for all projects.

2. Which cultures the web application use, the default culture and the
cookie name should be defined in each project.
Either by inserting them directly on the attribute or getting them
from Web.Config.

Basically everything is working fine.
What misses is an option to define those properties on the project not
on the attribute but somehow from the project web.config.
Isn't that basically the same as the above suggestion?  After all,
overrides only have an effect when you actually have an instance of the
class doing the overriding, which you can only have if you use the
project-specific type name, not the ProjectCultureAttribute type.


Well, I think the simplest way, assuming this is otherwise a wise thing
to do, would be to have each project somehow initialize the
ProjectCultureAttribute class with the necessary defaults, based on the
Config values.  Then ProjectCultureAttribute doesn't have to know
anything at all about the project itself.

Not sure if possible.
The culture attribute is defined on the BaseController before
everything else:

[Culture(Cultures = "pt-PT, es-ES")]
public class BaseController : Controller { // ... }
 
P

Peter Duniho

shapper said:
[...]
I would be fragile?
I mean, I can change the CookieName or CookiePath for example in the
Web.Config and the application would start using those new values.
A lot of other definitions can be change in Web.Config of Asp.Net
applications like ConnectionString, AuthenticationCookieName, etc.

Probably I misunderstood you.

The fragility isn't with respect to having configuration-specific
strings. It's that you (apparently) have a code attribute that is
mutable and depends on the configuration-specific strings. That's
unusual for code attributes, and could cause a code maintenance problem
later (e.g. because someone used the attribute thinking it's immutable).
[...]
Yes, you could do that. But then what of code in the Infrastructure.dll
or other external assemblies that want to use ProjectCulture, but depend
on your main project's settings? Or do you not care about that?

I am not sure that I am following you but:
1. The InfrastructureCultureAttribute should only contain the process
of setting the culture.
The process on that code is the same for all projects.

Where can the derived ProjectCulture sub-class be used? Only in one
assembly in an entire process? Are there no uses of ProjectCulture in
the Infrastructure.dll assembly, nor in any other assemblies used by the
process?

That's the point of my question. If the only place where the
configuration information is used is in the same assembly where you
declare your subclass of ProjectCultureAttribute, then that particular
issue is probably not a problem. But otherwise, it is.
2. Which cultures the web application use, the default culture and the
cookie name should be defined in each project.
Either by inserting them directly on the attribute or getting them
from Web.Config.

Part of the problem here is that it's still not clear why you are
embedding mutable culture information into a code attribute.

Even if you wanted to mark certain methods as culture-dependent somehow,
I would think that you'd still want some _other_ code just to detect
that, and then do the appropriate thing based on the attribute, rather
than embedding the culture information in the attribute itself.

After all, a class marked by this attribute doesn't wind up bound to a
specific culture. That's the whole point of making the default depend
on the configuration, right?

But, without a concise-but-complete code example that clearly shows the
expected use and circumstances of this attribute, it's hard to know for
sure.
Basically everything is working fine.
What misses is an option to define those properties on the project not
on the attribute but somehow from the project web.config.

I'm still not clear on why something that is named, and seems to be
used, in a project-wide way is found in a code attribute applied to
specific types within a project.
[...]
Well, I think the simplest way, assuming this is otherwise a wise thing
to do, would be to have each project somehow initialize the
ProjectCultureAttribute class with the necessary defaults, based on the
Config values. Then ProjectCultureAttribute doesn't have to know
anything at all about the project itself.

Not sure if possible.

If you aren't sure, then for sure no one else is.
The culture attribute is defined on the BaseController before
everything else:

[Culture(Cultures = "pt-PT, es-ES")]
public class BaseController : Controller { // ... }

The attribute itself is initialized based on what's written in the
declaration. But, presumably you actually _use_ that initialized state
somewhere. You're already proposed leaving members of the attribute
uninitialized (or rather, initialized to the default of "null"). So
initialization of the attribute is a foregone conclusion, based on your
description.

That leaves the _use_ of the attribute. Presumably, that use takes
place at run-time, since you want it to depend on the configuration
file. And if it takes places at run-time, presumably it _might_ take
place after such time as the configuration is known and could be used to
initialize some static data in the ProjectCultureAttribute class, shared
by all of the various instances you've created by using the class as an
attribute for types.

Of course, this is pure speculation. Until such time as you are willing
to post a proper code example, no one but you can know whether such an
approach would work.

Pete
 
S

shapper

shapper said:
[...]
I would be fragile?
I mean, I can change the CookieName or CookiePath for example in the
Web.Config and the application would start using those new values.
A lot of other definitions can be change in Web.Config of Asp.Net
applications like ConnectionString, AuthenticationCookieName, etc.
Probably I misunderstood you.

The fragility isn't with respect to having configuration-specific
strings.  It's that you (apparently) have a code attribute that is
mutable and depends on the configuration-specific strings.  That's
unusual for code attributes, and could cause a code maintenance problem
later (e.g. because someone used the attribute thinking it's immutable).

That's the point ... Ok the InfrastructureCultureAttribute might be
used by other people.

However, the ProjectCultureAttribute is to be used by me only on each
of my projects.
[...]
Yes, you could do that.  But then what of code in the Infrastructure..dll
or other external assemblies that want to use ProjectCulture, but depend
on your main project's settings?  Or do you not care about that?
I am not sure that I am following you but:
1. The InfrastructureCultureAttribute should only contain the process
of setting the culture.
   The process on that code is the same for all projects.

Where can the derived ProjectCulture sub-class be used?  Only in one
assembly in an entire process?  Are there no uses of ProjectCulture in
the Infrastructure.dll assembly, nor in any other assemblies used by the
process?

No, ProjectCulture will be used only on the Presentation project.

It would be useful to use the value of the CookieName defined in
WebConfig (Obtained on my code through Config.CookieName).
This way if I change in Web.Config the CookieName it will change
everywhere.
Not only in the attribute but also in other parts of the code that use
the same Cookie.
Like the buttons to change from one Culture to another and the action
that performs it.

In ASP.NET all cookie names can be defined in Web.Config. Exemple:
Session Cookie, Authentication Cookie, etc.
That's the point of my question.  If the only place where the
configuration information is used is in the same assembly where you
declare your subclass of ProjectCultureAttribute, then that particular
issue is probably not a problem.  But otherwise, it is.

Yes, the Configuration and ProjectCultureAttribute are only used in
the same project. The PresententationProject.
Part of the problem here is that it's still not clear why you are
embedding mutable culture information into a code attribute.

This is how it is not in ASP.NET MVC ... Attributes are filters to
actions.
They perform something before or after the action is executed.
Even if you wanted to mark certain methods as culture-dependent somehow,
I would think that you'd still want some _other_ code just to detect
that, and then do the appropriate thing based on the attribute, rather
than embedding the culture information in the attribute itself.

After all, a class marked by this attribute doesn't wind up bound to a
specific culture.  That's the whole point of making the default depend
on the configuration, right?

To be honest the two important things I would like to define in
Web.Config is DefaultCulture and CookieName.
CookieName because of me and so I have that name in central place
where I can change it without recompile and access it everywhere on my
code.
DefaultCulture because the client in the future might want to change
that value.
But, without a concise-but-complete code example that clearly shows the
expected use and circumstances of this attribute, it's hard to know for
sure.


I'm still not clear on why something that is named, and seems to be
used, in a project-wide way is found in a code attribute applied to
specific types within a project.

Let me say this:

InfrastructureCultureAttribute should not know what Cultures the
project will be used, what is the DefaultCulture or the CookieName.
It should be only include the process of setting culture, using a
filter, that is applied to the action.

Those three projects are defined on the project itself.
If it would be possible to have two defined on Configuration File
great for easy update without recompile and easy and "central" access.
[...]
Well, I think the simplest way, assuming this is otherwise a wise thing
to do, would be to have each project somehow initialize the
ProjectCultureAttribute class with the necessary defaults, based on the
Config values.  Then ProjectCultureAttribute doesn't have to know
anything at all about the project itself.
Not sure if possible.

If you aren't sure, then for sure no one else is.
The culture attribute is defined on the BaseController before
everything else:
  [Culture(Cultures = "pt-PT, es-ES")]
  public class BaseController : Controller { // ... }

The attribute itself is initialized based on what's written in the
declaration.  But, presumably you actually _use_ that initialized state
somewhere.  You're already proposed leaving members of the attribute
uninitialized (or rather, initialized to the default of "null").  So
initialization of the attribute is a foregone conclusion, based on your
description.

That leaves the _use_ of the attribute.  Presumably, that use takes
place at run-time, since you want it to depend on the configuration
file.  And if it takes places at run-time, presumably it _might_ take
place after such time as the configuration is known and could be used to
initialize some static data in the ProjectCultureAttribute class, shared
by all of the various instances you've created by using the class as an
attribute for types.

Of course, this is pure speculation.  Until such time as you are willing
to post a proper code example, no one but you can know whether such an
approach would work.

I will when I figure out where to start. :)
 
P

Peter Duniho

shapper said:
[...]
Part of the problem here is that it's still not clear why you are
embedding mutable culture information into a code attribute.

This is how it is not in ASP.NET MVC ... Attributes are filters to
actions.
They perform something before or after the action is executed. [...]

If this "mutable attribute" is a standard pattern in ASP.NET, then it
seems to me that you would be much better served by posting your
question to the ASP.NET-specific newsgroup, where you should find people
who are more accustomed to the particular usage you're implementing.

Frankly, the whole thing is a bit foreign to me, so I may not have the
best perspective on what it is exactly you're trying to do. That may be
true for all the other people who read this newsgroup and haven't even
replied to your question. :)

Pete
 
S

shapper

shapper said:
[...]
Part of the problem here is that it's still not clear why you are
embedding mutable culture information into a code attribute.
This is how it is not in ASP.NET MVC ... Attributes are filters to
actions.
They perform something before or after the action is executed. [...]

If this "mutable attribute" is a standard pattern in ASP.NET, then it
seems to me that you would be much better served by posting your
question to the ASP.NET-specific newsgroup, where you should find people
who are more accustomed to the particular usage you're implementing.

Frankly, the whole thing is a bit foreign to me, so I may not have the
best perspective on what it is exactly you're trying to do.  That may be
true for all the other people who read this newsgroup and haven't even
replied to your question.  :)

Pete

No problem Pete.
I think I will maybe follow another approach.

Thank You for the Help,
Miguel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top