ASP.NET manage site settings globally using database - c#

I am working on a project where I need to store settings for various areas in the application. These settings aren't stored in the app.config because there is an admin page where the admin can change the settings (client does not want these settings in the app.config)
I tried to implement a static class to access the settings globally but my concern is using the dbcontext in a static class as I don't think it's the best choice as well i'd like the settings to be strongly-typed and right now everything is a string.
I am not sure how else I can access my appsettings table in the database and still make it easy to call throughout the application, like ConfigurationManager.AppSetting["settingName"];
public static class AppManager
{
private static readonly IUnitOfWork UnitOfWork = new UnitOfWork(new DatabaseContext());
public static IEnumerable<AppSetting> GetAll()
{
return UnitOfWork.AppSettings.GetAll();
}
public static AppSetting Get(Guid id)
{
return UnitOfWork.AppSettings.Get(id);
}
public static string GetValue(string name)
{
return UnitOfWork.AppSettings.GetValue(name);
}
public static void Update(string name, string value)
{
var setting = UnitOfWork.AppSettings.Get(name);
if(setting == null) return;
setting.Value = value;
UnitOfWork.Complete();
}
}

Related

Should I define methods as static in class library to use in Console Application

Scenario: I have a console application which references couple of class libraries. ClassLibEmployee pulls the data from SQL database and returns a List. I need to loop through the list of Employee's and send that to a WebAPI and update SQL DB with status. I created ClassLibPay which a wrapper for WebAPI.
ClassLibEmployee.EmployeeData ed = new ClassLibEmployee.EmployeeData();
var elist = ed.PullEmployees();
foreach (Employee e in elist) {
bool stat = ClassLibPay.ServiceWrap.Sendtopay(e.Id, e.Name, e.Pay, e.ExemptFlag, e.Hours);
ed.ChageStatus(e.Id, e.Name, e.Pay, e.ExemptFlag, e.Hours, stat);
}
In ClassLibEmployee, I defined class as public class EmployeeData
In ClassLibPay, I defined class as public static class ServiceWrap
Questions:
since I will be calling ChangeStatus method in EmployeeData for each employee, should that be a static class?
ServiceWrap is calling a service, is there a way to avoid creating instance of the service, for every Sendtopay call?
Console App
--References ClassLibEmployee
public class EmployeeData
{
public List<Employee> PullEmployees()
{
}
}
ConsoleApp
--References ClassLibPay
-- ClassLibPay calls a WebAPI
public static class ServiceWrap
{
public static bool Sendtopay(int id, string name, decimal pay, bool flg, int hours)
{
using (EDataSvc service = new EDataSvc())
{
service.serviceMethod(id,name,pay,flg,hours);
}
}
}
To prevent creating every time class, you definitely should move to DI way as Michael said.
This is very simple example how to use DI with console application based on Autofac library. Below we have Main console application and two classes where one is our wrapper(where maybe you want to prepare your data, and eDataService which should just send data to back-end. We register both classes as PerLifeTimeScope(here, this is singleton's - in another words have only one instance if we get it from the DI container). Of course you can choose ready frameworks with already integrated DI containers.
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
builder.RegisterType<EDataSvc>().InstancePerLifetimeScope();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<MyService>();
service.MakeRequestAsync("test");
}
}
}
public class EDataSvc
{
public void SendRequestAsync()
{
//TODO:Send request
}
}
public class MyService : IMyService
{
private EDataSvc _eDataService;
public void MakeRequestAsync(EDataSvc eDataSvc)
{
_eDataService = eDataSvc;
}
public void MakeRequestAsync(string parameter)
{
//TODO prepare your data or additional logic
_eDataService.SendRequestAsync();
}
}
public interface IMyService
{
void MakeRequestAsync(string parameter);
}

Failing to pass Android Context using Autofac

I've decided to give Xarmarin a try, and I'd like to pass the android context.
I did a similar idea like this with Android and Roboguice back in the day. They had a provider factory, which would allow you to pass that item around to inject via properties.
I'd like to attempt this approach with IoC (Autofac ideally). I've followed this example: http://arteksoftware.com/ioc-containers-with-xamarin/
I'd like to add that I'm finding it difficult with services where I'd like to inject instances via the constructor.
Were you all able to do this?
I've decided to give Xarmarin a try, and I'd like to pass the android context.
Directly pass the android context? No, there is no way to do that. The Interface is defined in PCL, but there is no proper container(type) in PCL to accept the context instance.
But you can define your own Interface and class to leverage the Context instance:
Example based on the demo of the blog you posted (leverage the context to read a txt file in Assets folder):
Add a txt file(abc.txt) in Assets folder and set it's BuildAction as AndroidAssets.
Define a new Interface in PCL:
public interface IContextUtility
{
string GetAssetTxt(string str);
}
Add a variable of IContextUtility in MainViewModel.cs:
public class MainViewModel
{
private readonly IPlatform _platform;
private readonly ISettings _settings;
private readonly IContextUtility _contextUtility;
public MainViewModel (IPlatform platform, ISettings settings,IContextUtility contextUtility)
{
_settings = settings;
_platform = platform;
_contextUtility = contextUtility;
}
public string Abc
{
get {
return _contextUtility.GetAssetTxt("abc.txt");
}
}
...
}
Add IContextUtility implementation in Android Project:
public class MyContextUtility : IContextUtility
{
public string GetAssetTxt(string str)
{
string strToReturn = null;
using (var stream = Application.Context.Assets.Open(str))
{
using (StreamReader reader = new StreamReader(stream))
{
strToReturn=reader.ReadToEnd();
}
}
return strToReturn;
}
}
Register a new instance in App.cs:
[Application(Icon="#drawable/icon", Label="#string/app_name")]
public class App : Application
{
public static IContainer Container { get; set; }
public App(IntPtr h, JniHandleOwnership jho) : base(h, jho)
{
}
public override void OnCreate()
{
var builder = new ContainerBuilder();
builder.RegisterInstance(new MyContextUtility()).As<IContextUtility>();
...
}
}
Now, you can use it in your MainActivity:
var text = viewModel.Abc;

ASP.NET MVC guidelines for static classes for database access

The way I am utilising the MVC pattern at the moment in my ASP.NET application (using Entity Framework) is as follows:
1) My Models folder contains all EF entities, as well as my ViewModels
2) I have a Helpers folders where I store classes created for the purposes of the particular application.
3) In my Helpers folder, I have a static class named MyHelper which contains methods that access the DB using EF.
namespace myApp.Helpers
{
public static class MyHelper
{
public static async Task<ProductVM> GetProductAsync(int productId)
{
using (var context = new myEntities())
{
return await context.vwxProducts.Where(x => x.ProductId == productId).Select(x => new ProductVM { A = x.A, B = x.B }).FirstOrDefaultAsync();
}
}
}
}
4) My controllers then call these functions where necessary:
namespace myApp.Controllers
{
public class ProductController : Controller
{
[HttpGet]
public async Task<ActionResult> Index(int productId)
{
var productVM = await MyHelper.GetProductAsync(productId);
return View(productVM);
}
}
}
I usually encounter comments in SO of the type "don't use a static class, static classes are evil, etc". Would this apply in such a scenario? If yes, why? Is there a better 'structure' my app should follow for best practices and for avoiding such pitfalls?
You can't really use a static class for this. Your Entity Framework context should have one and only one instance per request. Your methods here instantiate a new context for each method, which is going to cause a ton of problems with Entity Framework.
The general concept is fine, but your MyHelper class should be a normal class. Add a constructor that takes an instance of your context, and then use a DI container to inject the context into the helper class and the helper class into your controller.
UPDATE
Helper
namespace myApp.Helpers
{
public class MyHelper
{
private readonly DbContext context;
public MyHelper(DbContext context)
{
this.context = context;
}
public async Task<ProductVM> GetProductAsync(int productId)
{
return await context.vwxProducts.Where(x => x.ProductId == productId).Select(x => new ProductVM { A = x.A, B = x.B }).FirstOrDefaultAsync();
}
}
}
Controller
namespace myApp.Controllers
{
public class ProductController : Controller
{
private readonly MyHelper myHelper;
public ProductController(MyHelper myHelper)
{
this.myHelper = myHelper;
}
[HttpGet]
public async Task<ActionResult> Index(int productId)
{
var productVM = await myHelper.GetProductAsync(productId);
return View(productVM);
}
}
}
Then, you just need to set up a DI container to inject everything. The code for that is entirely dependent on which container you end up going with, so I can't really help you further. It's usually pretty straight-forward, though. Just read the docs for the container. You'll want to set the life-time scope of your objects to the request. Again, it's different for different containers, but they'll all have some sort of request-scope.
I was thinking to add comment to ChrisPratt's answer, but it ended being too long, so let me add separate answer.
Basically, this is not a life/death choice. Sure, static methods are not as flexible as classes for db access. But they are not bad per-se. One DbContext per request is a something to aim for. It is not an absolute must. It is kinda like dependency injection - you get more flexibility and in turn increase code complexity.
Look at these three questions and their answers, by taking into account everything they say, I'm sure you'll be able to answer your question yourself:
Why would I use static methods for database access
When to use static classes in C#
One DbContext per web request... why?
EDIT: Chris left good comment on my answer and I've changed answer a bit to take into account what he said.
Your idea is correct and I use it always. But the style is like this:
1) For each entity (i.e User) we have a static class inside Providers folder. In this class we can do general methods (i.e create, Get, GetAll , ..)
public static class Users
{
public static IEnumerable<kernel_Users> GetAll()
{
Kernel_Context db = new Kernel_Context();
return db.kernel_Users;
}
public static kernel_Users Get(int userId)
{
Kernel_Context db = new Kernel_Context();
return db.kernel_Users.Where(c => c.UserId == userId).FirstOrDefault();
}
...
}
2) We have another class that is not static.It is inside Models folder. This is the place that we can access to an instance of the entity :
public partial class kernel_Users
{
[Key]
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
[NotMapped]
public string FullName
{
get
{
return FirstName + " " + LastName;
}
}
public bool Delete(out string msg)
{
...
}
...
}
I use a static class that has the context injected into a static constructor for the purposes of loading a cache of data that rarely changes. And it (should) be thread safe. I hope this helps you, it's very handy in my experience:
public static class StaticCache<T> where T: class
{
private static List<T> dbSet;
public static Dictionary<string, List<T>> cache = new Dictionary<string, List<T>>();
private static readonly object Lock = new object();
public static void Load(DbContext db, string connStr, string tableName)
{
lock (Lock)
{
try
{
if (connStr != null)
{
using (db)
{
dbSet = db.Set<T>().ToList();
cache.Add(tableName, dbSet);
}
}
}
catch { }
}
}
}
void Testit()
{
var context = new YourContextSubClass(connStr);
StaticCache<TableEntity>.Load(context, connstr, "tableEntityNameString");
}

How do I handle a configuration class that are loaded at runtime with dependency injection?

I'm currently trying to work with dependency injection and so far I love. But it's one thing I can't really get my head around and where my current solution just seems wrong.
I'm working with WPF, MVVM and many of the classes I inject need an instance of a project configuration class that isn't initialized until the user create or open a new project in the application.
So my current solution is to have a "ConfigurationHandler" with load/save method and a property that hold an instance of the configuration class after it's loaded. I inject ConfigurationHandler to the others classes and then they can access the configuration after it's loaded. But it seems weird to let classes that never should save/load configuration handle the whole "ConfigurationHandler" and 100% they would just use it to access the configuration instance likt this:
var configuration = configurationHandler.Configuration;
Another problem is that if they try to access the configuration before it's loaded they will get exception (should not really happen as you can't do anything before a project is created/loaded, but still).
But the only other solution I can think of is to use "intialize" methods after a project is created/open but that seems just as bad.
So how do you usually handle cases like this?
Edit: Should add that this configuration class handle information like project path, project name, etc so have nothing to do with the dependency injection itself.
If your configuration is static (read: It's only read during startup of your application, such as from project.json or Web.Config), you can also set it during app startup/the composition root.
The new ASP.NET 5 uses it heavily and it works very well. Basically you will have an IConfiguration<T> interface and a POCO class, which you set up during the app startup and can resolve/inject it into your services.
public interface IConfiguration<T> where T : class
{
T Configuration { get; }
}
And it's default implementation
public interface DefaultConfiguration<T> where T : class
{
private readonly T configuration;
public T Configuration {
return configuration;
}
public DefaultConfiguration<T>(T config)
{
this.configuration = this.configuration;
}
}
And your POCO class
public class AppConfiguration
{
public string OneOption { get; set; }
public string OtherOption { get; set; }
}
In your composition root, you would then register it, like
// read Web.Config
Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
container.AddSingleton<IConfiguration<AppConfiguration>>(new DefaultConfiguration<AppConfiguration>(
new AppConfiguration
{
OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
})
);
And finally, all you have to declare in your services is
public class MyService : IMyService
{
public MyService(IUserRepository, IConfiguration<AppConfiguration> appConfig)
{
...
if(appConfig.OneOption=="someValue") {
// do something
};
}
}
Finally you can make this a bit easier to configure, if you write an extension method like
public static class MyContainerExtension
{
public static void Configure<T>(this IMyContainer container, Action<T> config) where T : class, new()
{
var t = new T();
config(t);
container.AddSingelton<IConfiguration<T>>(t);
}
}
Then all you need to do is
container.Configure<AppConfiguration>(
config =>
{
config.OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
config.OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
})
);
to set it up
Instead of Constructor Injection, consider using an Ambient Context approach.
The last type of DI we’ll discuss is making dependencies available
through a static accessor. It is also called injection through the
ambient context. It is used when implementing cross-cutting concerns.
This is a good option if the classes that need access to your configuration are of different types in different layers or libraries - i.e. is a true cross-cutting concern.
(Quote source)
Example, based on the classic Time Provider one from [Dependency Injection in .NET][2]
abstract class CustomConfiguration
{
//current dependency stored in static field
private static CustomConfiguration current;
//static property which gives access to dependency
public static CustomConfiguration Current
{
get
{
if (current == null)
{
//Ambient Context can't return null, so we assign a Local Default
current = new DefaultCustomConfiguration();
}
return current;
}
set
{
//allows to set different implementation of abstraction than Local Default
current = (value == null) ? new DefaultCustomConfiguration() : value;
}
}
//service which should be override by subclass
public virtual string SomeSetting { get; }
}
//Local Default
class DefaultCustomConfiguration : CustomConfiguration
{
public override string SomeSetting
{
get { return "setting"; }
}
}
Usage
CustomConfiguration.Current.SomeSetting;
There are other DI Patterns that could be used, but require changes to the class that need it. If Configuration is a cross cutting concern Ambient Context could be the best fit.
Constructor Injection Example
public SomeClass(IConfiguration config)
{
}
Property Injection
public SomeClass()
{
IConfiguration configuration { get; set; }
}
Method Injection
public SomeClass()
{
public void DoSomethingNeedingConfiguation(IConfiguration config)
{
}
}
There is also Service Locator, but Service Locator is (IMO) an anti-pattern.

How do I use multiple databases with sqlmembershipprovider at runtime?

I have a web application and two sql databases. My client wants different languages and I have solved it with resource files one the public parts of the site, no probs. The thing is they have two databases with the same structure and type of data but in different languages, and the users differs aswell. I have overrided "Initialize" from SqlMembershipProvider as:
public class MyqlMembershipProvider : SqlMembershipProvider
{
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
var connectionString = GetConnectionStringFromSelectedLanguage();
config["connectionStringName"] = connectionString;
base.Initialize(name, config);
}
}
But the Initialize gets invoked only once, I need to set the connectionString everytime I use Membership.yadayada depending on the language selected. I dont want to use Membership.Providers["one_provider"].DeleteUser(a_username) because It is used EVERYWHERE. How should I go about this, is there anything else I can override?
/Mike
This isn't possible. The membership provider is a static object initialized once and shared between users. Changing any of the values for it changes them for all users of the application. See this answer for a more thorough explanation...
How do I use multiple databases with sqlmembershipprovider at runtime?
You could use a DependencyInjection framework like Ninject for the application and build your repositories based on a named dependency.
For example, you could have an Interface which just provides the connection string name:
Interface IConnectionProvider
{
ConnectionName { get;}
}
class LanguageAProvider : IConnectionProvider
{
public string ConnectionName { get { return "dbnameLangA"; } }
}
class LanguageBProvider : IConnectionProvider
{
public string ConnectionName { get { return "dbnameLangB"; } }
}
public class MyqlMembershipProvider : SqlMembershipProvider
{
private readonly string _connectionStringName;
public MyqlMembershipProvider (IConnectionProvider connection)
{
_connectionStringName = connection.ConnectionName;
}
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
var connectionString = GetConnectionStringFromSelectedLanguage();
config[_connectionStringName] = _connectionStringName;//I'm not sure how you need to use the connection name here.
base.Initialize(name, config);
}
}
I haven't tested any of this, but it could be an idea. You could then have Named Bindings to select the required dependency at run time.
I need to set the connectionString everytime I use Membership.yadayada depending on the language selected
This isn't feasible: consider what happens when two requests from users with different languages are processed concurrently. If you changed the connection string for user A, it would affect user B.
What you could do is write a custom Membership provider which aggregates two (or more) SqlMembershipProviders, and redirects based on the current user's language.
public class MyMembershipProvider : MembershipProvider
{
private Dictionary<string, MembershipProvider> _languageMembeshipProviders;
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
... create an SqlMembershipProvider for each language and add to
... the languageMembeshipProviders dictionary
}
public override bool ValidateUser(...)
{
... Get language from HttpContext.Current somehow
... select a provider from the dictionary
... call the provider
}
}
However I find it difficult to understand how this could work in practice. Presumably there's something in the request (querystring, cookie, accept-languages header) to indicate the user's language. If so, a user could potentially be authenticated using one language, then switch to access the other database by changing the language in his request.
I'd have thought it would be simpler and cleaner to have separate applications for each language. If a user arrives on site A indicating he wants language B, then he should be redirected to the application B.

Categories

Resources