Using ConfigurationManager.AppSettings.Get() value as a constant string

D

dushkin

Hi all.

I am using ConfigurationManager.AppSettings.Get() to get a string
value from a web.config file.
I must pass it as a constant string value to an attribute.

How can I do that? How can I pass the string value as constant string
to the attribute?

Many thanks!
 
J

Jeff Johnson

I am using ConfigurationManager.AppSettings.Get() to get a string
value from a web.config file.
I must pass it as a constant string value to an attribute.

How can I do that? How can I pass the string value as constant string
to the attribute?

Can you please give a sample of what you're trying to do, even if the code
doesn't work? I'm not positive I understand your question, although I have a
vague idea.
 
D

dushkin

Depends on your definition of "attribute".  The word can mean a great
many number of different things.

But, if you mean a code attribute — i.e. used to initialize a type that
inherits System.Attribute, in the context of a square-bracket
declaration in your C# code — then the answer is you can't.  That's
strictly compile-time, so unless you actually compile the block of code
in question at run-time, it's not possible.

Now, you can in fact compile code at run-time, so if you absolutely need
to accomplish your goal this way, that's an alternative approach you
might use.  But that adds a whole new layer of complexity to your
problem, and IMHO is not normally going to be the correct approach to
dealing with things that are supposed to be controlled via a
configuration file.

(I hesitate to even mention, but if the Attribute sub-class you're
dealing with is mutable, I suppose there's a chance you could use
reflection to retrieve the object and then change it after the fact.
Attribute sub-classes are supposed to be immutable, and of course even
if not, success in that approach would depend on the exact timing at
which the Attribute object is used.  But it might work.  I wouldn't
recommend it though.).

Much better would be to find a different way altogether to control
whatever it is you're trying to control.

Pete

Hi Pete, thank you. Well I also came to the conclusion (together with
some friends) that it is probably not possible. Yes it is a
System.Atrribuye dervied object.

Thanks,
 
D

dushkin

Can you please give a sample of what you're trying to do, even if the code
doesn't work? I'm not positive I understand your question, although I have a
vague idea.

Hi,

It is probably not possible. See my answer to Peter below.

Thanks.
 
J

Jeff Johnson

Can you please give a sample of what you're trying to do, even if the code
doesn't work? I'm not positive I understand your question, although I have
a
vague idea.
It is probably not possible. See my answer to Peter below.

Yeah, I kind of figured that's what you were trying to do.
 
A

Arne Vajhøj

I am using ConfigurationManager.AppSettings.Get() to get a string
value from a web.config file.
I must pass it as a constant string value to an attribute.

How can I do that? How can I pass the string value as constant string
to the attribute?

This is going to be a long post, but the problem has
some interesting aspects (no pun intended).

I will assume that the scenario is:
* you have a third party library that contains:
- a definition of an attribute with a value
- a service that process objects of classes
with that attribute
* you have your own code that contains:
- one or more classes with that attribute
- calls to that service
* you want to make the value of the attribute
configurable instead of hardcoded

Simple example.

External library:

using System;

namespace F
{
public class SomeAttribute : Attribute
{
private String sv;
public string SomeValue
{
get { return sv; }
set { sv = value; }
}
}
public class SomeService
{
public void Process(object o)
{
object[] attrs =
o.GetType().GetCustomAttributes(typeof(SomeAttribute), true);
if(attrs.Length > 0)
{
string val = ((SomeAttribute)attrs[0]).SomeValue;
Console.WriteLine("processing with SomeAttribute
SomeValue=" + val);
}
else
{
Console.WriteLine("processing without SomeAttribute");
}
}
}
}

Your code:

using System;

using F;

namespace E
{
[SomeAttribute(SomeValue="ABC")]
public class SomeData
{
}
public class Program
{
public static void Main(string[] args)
{
SomeData o = new SomeData();
SomeService srv = new SomeService();
srv.Process(o);
}
}
}

This works fine, but the value for the attribute is hardcoded
to "ABC".

What you want to do is:

using System;

using F;

namespace E
{
[SomeAttribute(SomeValue="cfg:some")]
public class SomeData
{
}
public class Program
{
public static void Main(string[] args)
{
SomeData o = new SomeData();
SomeService srv = new SomeService();
srv.Process(o);
}
}
}

with an app.config (you are actually using web.config, but
I am testing with a Console app and it really does not change
anything):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="some" value="ABC"/>
</appSettings>
</configuration>

That does obviously not work out of the box.

You can not change the behavior of the library without changing
the library.

If you could change the source code of the library, then it
would be easy.

using System;
using System.Configuration;

namespace F
{
public class SomeAttribute : Attribute
{
private String sv;
public string SomeValue
{
get { return sv; }
set { sv = value; }
}
}
public class SomeService
{
public void Process(object o)
{
object[] attrs =
o.GetType().GetCustomAttributes(typeof(SomeAttribute), true);
if(attrs.Length > 0)
{
string val = ((SomeAttribute)attrs[0]).SomeValue;
if(val.StartsWith("cfg:"))
{
val =
ConfigurationManager.AppSettings[val.Substring(4)];
}
Console.WriteLine("processing with SomeAttribute
SomeValue=" + val);
}
else
{
Console.WriteLine("processing without SomeAttribute");
}
}
}
}

works fine.

But it assumes that:
- you have access to the source code of the library
- the license of the library allows modification
- you are willing to take on the burden of maintaining those
modifications when you need to update the library

If those assumptions were met, then you would not be
asking this question here.

So let us look at alternatives.

Decompiling the binaries, modifying the generated
souce code and rebuilding!?!?

It does get rid of the requirement for source code.

But it assumes that:
- the license of the library allows modification
- you are willing to take on the burden of maintaining those
modifications when you need to update the library
[and that burden is a lot bigger than when using the real
source code]

Not recommendable.

Using an AOP static weaver to write aspect that does
what you want and weave them into the binaries!?!?

It does get rid of the maintenance problem.

But it assumes that:
- the license of the library allows modification
- you can find a good AOP static weaver for .NET

The license is something you will need to deal with
no matter what.

Surprisingly it can be difficult to find a good
AOP static weaver for .NET.

AspectDNG were my favorite for many years. It worked
great with .NET 1.1 and I could get it to work with
2.0, but I have not been able to get it to work
properly with 4.0. The author dropped the project
in February 2008. And a quick attempt to update
the code by getting a newer version of Cecil did
not work out.

SheepAspect/SheepAOP looks rather promising. But I
have simply not been able to get it to work properly.
If anyone want to give it a try then it is available
via NuGet.

I could not find any other promising looking
candidates.

There are plenty of dynamic weavers, but that
is a rather different animal than a static weaver.

So what to do to demonstrate the technique?

I wrote my own!

When the following aspect:

using System;
using System.Configuration;

using Vajhoej.StaticWeaver;

[Aspect]
public class AttrFix
{
[Pointcut(Signature="* F.SomeAttribute::get_SomeValue()")]
public static void AttrFixPointcut() { }
[AfterCallAdvice(Pointcut="AttrFixPointcut")]
public static void AttrFixAdvice(MethodJoinpoint mjp)
{
if(((string)mjp.Result).StartsWith("cfg:"))
{
mjp.Result =
ConfigurationManager.AppSettings[((string)mjp.Result).Substring(4)];
}
}
}

is weaved into the library DLL, then the code works
as desired.

The AOP solution is worth considering if you are OK
license wise.

Arne

PS: No, I did not write it just for this post - I plan
on using it for other purposes as well.

PPS: It is called YAAOPF (Yet Another AOP Framework) and
you can get a copy as open source (Apache 2.0 license)
if someone should be interested!
 

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