I have a class library used in windows (WPF) and web (ASP.NET) context. The library has settings that are rather user-scoped, if used in windows context and that have to be application-scoped, if used in web context. I would like to declare them as user-scoped and use the default values as “pseudo-application-scoped”. My problem is, that web applications ban user-scoped settings by throwing a configuration error.
What is the best way to handle this, preferably within the frameworks configuration system?
Ok, facing the unavoidable. There are no user-scoped settings in ASP.NET. Class libraries used in mixed client / server environments shouldn’t use them!
Here is the solution I ended with:
For the usage in a server environment (ASP.NET) all settings of class libraries have to be application-scoped.
I introduce a second set of settings for the usage in client environments (WPF). These settings have property names and types identical to the class libraries property names and types, but they can differ in scope and they are located in my main assembly.
With a small piece of code I extend the libraries setting class to inject the user-scoped settings.
namespace ClassLibrary.Properties
{
using System.Configuration;
public sealed partial class Settings {
private ApplicationSettingsBase injectedSettings;
public void InjectSettings(ApplicationSettingsBase settings)
{
injectedSettings = settings;
}
public override object this[string propertyName]
{
get
{
if (injectedSettings != null)
return injectedSettings[propertyName];
return base[propertyName];
}
set
{
base[propertyName] = value;
}
}
}
}
With this extension I can inject the second settings class into the library settings:
ClassLibrary.Properties.Default.InjectSettings(Application.Properties.Settings.Default);
Have a look at the SettingsProvider class by sub classing it you could create a compatible provider for a ASP.NET environment.
It might make changing the current code quite easy because you can keep the current code but have to add a different provider when in ASP.NET.
This gives a nice overview as well
Related
I`ve added a service Reference based on a local wsdl file to my .net core 6 application.But the Interface i get from the Reference gives me addidional data types.
If i implement the interface it should give me following method.
public Ack Heartbeat(Heartbeat parameter)
{
(my impl. here)
}
but instead its generating me
public HeartbeatResponse HeartbeatAsync(HeartbeatRequest request)
{
(my impl. here)
}
So for all my methods defined by the interface there is a new datatype with ...Response and ...Request
Ive read that this could have to do something with the setting "always generate message contracts" in the add sercvice reference setings. But i have`nt checked this setting.
I have a code library I have written which can be utilized in both desktop applications and on a web server. That library sometimes needs to know which environment it's running in.
In the past I have relied on System.Web.Hosting.HostingEnvironment.IsHosted to tell if the code is running on a web server. Unfortunately asp.net core mvc does not have access to the System.Web namespace so I need another mechanism.
How can the code tell if it's running on a web server if one of those possibilities is asp.net core mvc?
Answering my own question in case it helps others.
It's been mentioned that one way to determine whether the code is running on a web server or desktop app is to look at the name of the process it's running in. This is definitely possible, but I have little control over what the process name is for a web application and the name is likely to change in the future if history is any indication.
So instead, I chose to make the determination based on the application's config file name. This file name is different for web apps and desktop apps and it's something that's more under my control as a developer.
The method I wrote to do this is:
public bool IsWebServer {
get {
string file = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile.ToLower();
//web.config used by asp.net 4.X,
//app.config used by MVC Core
//NameOfTheApp.exe.config used by desktop applications
if(file.Contains("web.config") || file.Contains("app.config")) {
return true;
}
return false;
}
}
Unfortunately, there is no currently equivalent API. When you look at how that property works, you can easily do something equivalent yourself--without making assumptions about which server is hosting your application.
You'll have to set up your API with a static public property:
namespace My.Project
{
public static HostingEnvironment
{
public static bool IsHosted { get; private set; }
public static void SetIsHosted(this IServicesCollection services)
{
// you can grab any other info from your services collection
// if you want. This is an extension method that you call
// from your Startup.ConfigureServices method
IsHosted = true;
}
}
}
So now you have something that works with both ASP.Net MVC 5 and 4.5. You would integrate it in your Startup.ConfigureServices() method.
public void ConfigureServices(IServiceCollection services)
{
// Set up whatever services you want here.
// Make sure you have your My.Project namespace
// in your using statements so you can use the IsHosted()
// extension method
services.SetIsHosted();
}
The only difference between this solution and the legacy System.Web.Hosting.HostingEnvironment.IsHosted solution is that the flag was set by the framework when the application was started by IIS automatically. This is probably as close of an equivalent solution as you are going to get, while still allowing the ability to host anywhere.
I'm creating an ASP.NET Web API 2.1 site and as I want to inject dependencies directly into the controllers, I've created my own implementation of IDependencyResolver so that StructureMap will handle that for me.
public class StructureMapDependencyResolver : IDependencyResolver
{
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
return ObjectFactory.GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return ObjectFactory.GetAllInstances(serviceType).Cast<object>();
}
public void Dispose()
{
}
}
I've then told Web API to use this class by adding this line to the Application_Start method in Global.asax
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver();
That compiled but when I tried to access any of the API methods in a browser I got an error like this
No Default Instance defined for PluginFamily System.Web.Http.Hosting.IHostBufferPolicySelector, System.Web.Http
That one was relatively easy to solve as I added a line to my StructureMap configuration
this.For<IHostBufferPolicySelector>().Use<WebHostBufferPolicySelector>();
However then I got other similar errors for other System.Web.Http classes and while I could resolve some of them I am stuck on how to deal with 3 of them, namely ITraceManager, IExceptionHandler and IContentNegotiator.
The issue is that TraceManager which seems to be the default implementation of ITraceManager is an internal class and so I can't reference it in my StructureMap configuration.
So am I going about this completely the wrong way or is there some other way to inject these internal classes?
I'd like to give you a suggestion and explanation why not to go this way, and how to do it differently (I'd even say better and properly).
The full and complete explanation of the inappropriate IDependencyResolver design could be found here: Dependency Injection and Lifetime Management with ASP.NET Web API by Mark Seemann
Let me cite these essential parts:
The problem with IDependencyResolver
The main problem with IDependencyResolver is that it's essentially a Service Locator. There are many problems with the Service Locator anti-pattern, but most of them I've already described elsewhere on this blog (and in my book). One disadvantage of Service Locator that I haven't yet written so much about is that within each call to GetService there's no context at all. This is a general problem with the Service Locator anti-pattern, not just with IDependencyResolver.
And also:
...dependency graph need to know something about the context. What was the request URL? What was the base address (host name etc.) requested? How can you share dependency instances within a single request? To answer such questions, you must know about the context, and IDependencyResolver doesn't provide this information.
In short, IDependencyResolver isn't the right hook to compose dependency graphs. **Fortunately, the ASP.NET Web API has a better extensibility point for this purpose. **
ServiceActivator
So, the answer in this scenario would be the ServiceActivator. Please take a look at this answer:
WebAPI + APIController with structureMap
An example of the ServiceActivator:
public class ServiceActivator : IHttpControllerActivator
{
public ServiceActivator(HttpConfiguration configuration) {}
public IHttpController Create(HttpRequestMessage request
, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = ObjectFactory.GetInstance(controllerType) as IHttpController;
return controller;
}
}
All we can do with StructureMap, is in place. The key features of the Web API framework are still in place... we do not have to hack them. And we are also rather using DI/IoC then Service locator
Just try using UnityHierarchicalDependencyResolver instead of the other one. It worked for me. This is for future reference if somebody would like to use Unity
Today I am digging into WCF Data Service and I have a question regarding this. Can I create WCF Data service as Library and just only create WCF data Service in our existing web app and take reference that library using Factory property so service will deploy with existing web application.
As I know We can create WCF Service Library and only need to take reference that library in Web application like :
Create a WCF Library and implement service contract
Create a Web application and add new item as Wcf service file then take reference WCF library
<%# ServiceHost Service="MyServiceLibrary.MyService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" />
Instead of a service library, I want to create OData service library.
Thanks
Yes, you can host a WCF Data Service in your own assembly - with a few little tricks. I researched this a while ago and came up with these steps / instructions.
Here's how:
put your data model (EF Data Model) into its own assembly, let's call it DataModel
create a new class library project (call it MyDataServiceHost)
add a few references:
your DataModel assembly with the data layer
System.ServiceModel
System.ServiceModel.Web
System.Data.Services.Client
System.Data.Services - you cannot pick this from the usual Add Reference dialog under the .NET category - you need to browse for the assembly file. Find the directory C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0 (or C:\Program Files (x86)\... on a 64-bit machine) and pick the System.Data.Services.dll inside it
add a new class to that class library and call it e.g. YourDataService.cs - it will look something like this:
using System.Data.Services;
using System.Data.Services.Common;
using DataModel;
namespace MyDataServiceHost
{
public class YourDataService : DataService<YourModelEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
// Examples:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
}
You can name the class anything you like, and it has to derive from DataService<T> where T is the name of your data model; if you're using Entity Framework, it's the name of your object context class - typically something like (database)Entities or whatever you picked when you created the EDM
add another class to your new project, call it MyDataServiceHost.cs and it will look something like this:
using System;
using System.Data.Services;
using DataModel;
namespace MyDataServiceHost
{
public class MyDataServiceHost
{
public static void LaunchDataService(string baseAddress)
{
Uri[] baseAddresses = new Uri[1];
baseAddresses[0] = new Uri(baseAddress);
using(DataServiceHost host = new DataServiceHost(typeof(YourDataService), baseAddresses))
{
host.Open();
Console.WriteLine("DataService up and running.....");
Console.ReadLine();
host.Close();
}
}
}
}
It instantiates a DataServiceHost, which is derived from WebServiceHost (which in turn is derived from ServiceHost) and it will spin up the WCF Data Service runtime for you.
now you can start up your WCF Data Service from any app using:
MyDataServiceHost.LaunchDataService("http://localhost:4444/YourService");
last thing to remember: the app that you use to launch the WCF Data Service must have the connection string (the EDM connection string, if you're using Entity Framework) in its app.config (or web.config) in order for this to work!
In my experience, web.config files are widely reviled. In particular, I have found them difficult to manage when you have multiple environments to support, and fiddly to update due to the lack of validation at update-time and the verbosity of XML.
What are the alternatives?
I personally don't mind Web.Config for small one-off applications, but for anything substantial I avoid using them for application configuration.
Here's what I do...
I define one or more interfaces for my configuration depending on the complexity.
I create different implementations per environment (dev, stage, prod, etc.)
I use an abstract base class to define common configuration.
I then use Ninject for dependency injection so the appropriate implementation is provided depending on which environment I am targeting.
I always code to the configuration interfaces and benefit from compile time checks.
Here's an example...
// Config Contract
public interface IWebAppConfig
{
string SmtpHost { get; }
string RootUrl { get; }
}
// Define Common Config Values (values that don't change per environment)
public abstract class AbstractWebAppConfig : IWebAppConfig
{
public string SmtpHost { get { return "smtp.google.com"; } }
public abstract RootUrl { get; }
}
// Dev Config Settings
public class DevWebAppConfig : AbstractWebAppConfig
{
public override string RootUrl { get { return "http://localhost:1322"; } }
}
// Stage Config Settings
public class StageWebAppConfig : AbstractWebAppConfig
{
public override string RootUrl { get { return "http://stage.mysite.com"; } }
}
// Prod Config Settings
public class ProdWebAppConfig : AbstractWebAppConfig
{
public override string RootUrl { get { return "http://www.mysite.com"; } }
}
Advantages of this approach:
Type Safe
Configuration is represented as objects not key value pairs (useful for passing logical groupings of config values instead of multiple values)
Easier to Unit Test classes that are dependent on configuration values
Sharing configuration across multiple apps is trivial
Deploying the assembly that contains the configuration implementations will trigger a recycle of the application pool, much like re-deploying a web.config.
You may still use the web.config to define the environment, which is what I usually do by adding the following to the appSettings:
<appSettings>
<!-- accepts: dev|stage|prod -->
<add key="Env" value="dev" />
</appSettings>
Alternatively, it could be machine based by using Envrionment Variables, or some other construct.
How long has ASP.NET been in existence; how many production web sites are using it?
They're almost all using web.config, as it comes, out of the box. They can't be "reviling" it too much.
That said, look at the new features of ASP.NET in .NET 4.0, including configuration-specific web.config files, and xml-based transformations of web.config that permit environment-specific web.config versions to be generated at deployment time.
You may revile that a little less.
I strongly disagree with your assertion that web.config files are "widely reviled." In my experience, they're easy to maintain and manage, and in some cases are the only place you can put configuration data.
It's worth noting that VS2010 supports per-build configuration web.config transforms. I have a web.config, web.debug.config, and web.release.config. The debug and release files override the connection strings specified in web.config and replace them with the correct strings, for my debug and production SQL Servers, specifically. I'm also using this to make some AppSettings values config-specific.
Since you can add a build config for as many different targets or configurations as you require, I don't see why you'd feel the need to reinvent the wheel by devising another repository.
That said, you can use just about any repository for whatever data you want to store. A database, text config file of the format of your choice, encrypted image, or what have you.