I'm running on a windows 2008 server. I have one Web service which calls a wcf service.
Within the WCF service it attempts to cast a date 20/08/2010 which fails because it thinks it in US format not Austrlaian.
So far I have:
On control panel change the region to English Australian under format
Under the Administrative tab I have also set system local to English (Austrlian)
within IIS7 at the default web site level I have changed Culture and UI culture under the .Net globalization.
I've also done this at the Web service and WCF Nodes
I have added the following to the Web service and WCF apps web.config file
<globalization requestEncoding="utf-8"
responseEncoding="utf-8"
culture="en-AU"
uiCulture="en-AU" />
This finally changed the culture in the Web service but the WCF service remains US culture.
Can anyone tell me what else I can try?
The WCF will ignore your globalization configuration if you do not set aspNet compatibility:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
...
To use that mode your service class must have the attribute AspNetCompatibilityRequirements set to Allowed or Required:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ServiceClass
{
...
}
This could work if you want to apply the Culture and CultureUI from config file.
Or you could either try to force the Culture in your WCF service code, if you are sure that it will not change dynamically. For instance, in your service class constructor. Note that this is not a best practice, perhaps you should use a Context initializer, but this one is quite simple.
public ServiceClass()
{
...
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-AU");
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-AU");
}
More info:
setting-cultureinfo-on-wcf-service-calls
using-call-context-initializers-for-culture
The problem is in the culture that is set for a user used in the application pool.
I found the following way to resolve this issue:
If the application pools uses ApplicationPoolIdentity change it to NETWORKSERVICE (unfortunatly I didn't found how to set regional settings for ApplicationPoolIdentity)
Set regional settings you need (en-AU) on the current user and than copy them for the system accounts as described here.
You can do it in the Global.asax.cs file, in the Application_Start file:
using System.Threading;
using System.Globalization;
public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-AU");
}
}
Related
Our application (Server-side Blazor in .NET Core 3.1) runs within IIS on a Windows Server. We have multiple sites in IIS running the same application but with different URL's for different customers.
At startup in (ConfigureServices) we want to load customer configuration for the application from a config file. That way we can have multiple instances of the application running with different configs. Loading this information from the database is not an option because the config contains the details to connect to the database.
In ASP.NET Framework we would have access to the virtual path or (sub)domain name in the Global and then load the configuration based on that information.
We need the same access in our ASP.Net Core applications or another work around.
Is there any to achieve the same result?
A better way to distinguish sites is by URL. The domain name and port bound to each site in IIS will not be repeated.
You can refer to these code to get URL in startup.cs.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,IHostApplicationLifetime lifetime,IServiceProvider serviceProvider)
{
...other code...
lifetime.ApplicationStarted.Register(
() => logAddresses(app.ServerFeatures));
}
static void logAddresses(IFeatureCollection features)
{
var addressFeature = features.Get<IServerAddressesFeature>();
if (addressFeature != null)
{
foreach(var address in addressFeature.Addresses)
{
Console.Out.WriteLine(address);
}
}
}
I was able to grab the Application Pool ID from the Environment and then load the config section as the application config:
var appPool = Environment.GetEnvironmentVariable( "APP_POOL_ID", EnvironmentVariableTarget.Process )
van sectionname = SomeMagicToParseAppPool( appPool );
var config = Configuration.GetSection( sectionName );
if ( config == null ) throw new ApplicationException($" Cannot find config section for {host}");
services.Configure<ApplicationSettings>( config );
This allows me to load a different config for a different site. The only downside is that each application requires their own Application Pool. But that was already a requirement due to a .NET Core ASP.NET app having to run unmanaged in the Application Pool.
I have .net core standard class library which is essentially a DAL with several class methods that return collections and objects from a database. The connection string is in the appsettings.json file of the ASP.net 2 core web app. I also want to access this class library from a console app project where the configuration file with the connection string will be present in that console app project.
This was simple in .net prior to .net core. The DAL class library would just access the web.config from a web project and an app.config from a console application as it the library is referenced in both the web app and console apps. But it doesn't seem like this is at all possible.
I'm looking for the simple solution in .net core to get a connection string from web app or console app as the case may be.
Where you're probably going wrong is that you want to access configuration from your class library, but then you want to leak details specifically about the caller (That it will have a web.config).
But what if you decide in your Web Application you want to use Azure Key Vault or another secrets mechanism? Does your class library need to then change it's entire implementation to use Key Vault? And then does that mean your console application also has no option but to use Key Vault too?
So the solution is to use dependency inversion. Put simply, let's say I have code like the following :
interface IMyRepositoryConfiguration
{
string ConnectionString {get;}
}
class MyRepositoryConfiguration : IMyRepositoryConfiguration
{
public string ConnectionString {get;set;}
}
class MyRepository
{
private readonly IMyRepositoryConfiguration _myRepositoryConfiguration;
public MyRepository(IMyRepositoryConfiguration myRepositoryConfiguration)
{
_myRepositoryConfiguration = myRepositoryConfiguration;
}
}
Now in my startup.cs I can do something like :
services.AddSingleton<IMyRepositoryConfiguration>(new MyRepositoryConfiguration {//Set connection string from app settings etc});
And now my class library doesn't need to know exactly how those configuration strings are stored or how they are fetched. Just that if I request an instance of IMyRepositoryConfiguration, that it will have the value in there.
Alternatively of course, you can use the Options class too, but personally I prefer POCOs. More info here : https://dotnetcoretutorials.com/2016/12/26/custom-configuration-sections-asp-net-core/
It is very much possible to access "connection strings" or other configuration data easily in .Net core without much additional effort.
Just that the configuration system has evolved (into something much better) & we have to make allowances for this as well (& follow recommended practices).
In your case as you are accessing the connection string value in a standard library (intended to be reused), you should not make assumptions as how the configuration values will be "fed" to your class. What this means is you should not write code to read a connection string directly from a config file - instead rely on the dependency injection mechanism to provide you with the required configuration - regardless of how it has been made available to your app.
One way to do this is to "require" an IConfiguration object to be injected into your class constructor & then use the GetValue method to retrieve the value for the appropriate key, like so:
public class IndexModel : PageModel
{
public IndexModel(IConfiguration config)
{
_config = config;
}
public int NumberConfig { get; private set; }
public void OnGet()
{
NumberConfig = _config.GetValue<int>("NumberKey", 99);
}
}
In .net core, before the app is configured and started, a "host" is configured and launched. The host is responsible for app startup and lifetime management. Both the app and the host are configured using various "configuration providers". Host configuration key-value pairs become part of the app's global configuration.
Configuration sources are read in the order that their configuration providers are specified at startup.
.Net core supports various "providers". Read this article for complete information on this topic.
I have a WCF Service hosted in IIS. This solution is composed of 2 projects: Service and Data. Service depends on Data, like so:
Service -> Data
I've been trying to invert the dependency, like so:
Service <- Data
Which is quite a headache using WCF, since the WCF service constructor must be parameter-less (by default).
I hear it's possible to inject the dependency using Ninject and its WCF extension, so I tried to integrate it to my solution, but it's still not clear to me in which project should be the related files and references? What I did is :
Download Ninject using NuGet
Add Ninject to both my Data and Service projects (that created the NinjectWebCommon file in the App_Start folder of the Service Project
Create a IDataProxy interface in my Service project
Implement the interface in my Data project
Add a IDataProxy argument to the WCF service constructor
Added the factory configuration in the .svc file markup
Up to that point, I'm pretty sure I'm doing it right. Now the shaky part :
I created a DataInjectionModule in my data project with this code :
namespace Data
{
public class DataInjectionModule : NinjectModule
{
public override void Load()
{
Bind<IResolutionRoot>().ToConstant(Kernel);
Bind<ServiceHost>().To<NinjectServiceHost>();
Bind<IDataProxy>().To<DataProxy>();
}
}
}
I finally tried to register the service in the NinjectWebCommon files (of both projects to be sure) like that :
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IService>().To<Service>()
.WithConstructorArgument("IDataProxy", context => context.Kernel.Get<IDataProxy>());
}
When I try to start my service, I still get this :
The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.
I have a feeling that the problem resides in the fact that I did not bind my DataInjectionModule in the kernel, but if I try to do so, I must add a dependency from Service to Data, which is what I'm trying to avoid.
General expert advice would be greatly appreciated. Thanks.
Please check your point 6: "Added the factory configuration in the .svc file markup."
Have you done it properly?
The *.svc file should have this code:
Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory"
I have a Sharepoint 2010 webpart that calls a WCF service.
I've created a service proxy and manually coded the endpoint, see below.
In a conventional WCF client I'd use the config files for the configuration and use transforms when I was buiding for deployment to different environments.
How would I achieve the same through a Sharepoint webpart? I want to put the configuration somewhere that it can be changed for different build configurations.
ie. For a local deployment during testing, then a test server, production. We're trying to automate this as much as possible.
Thanks,
Tim
UPDATE:
I'm aware that you need to put config data in the web.config file in sharepoint. I'm looking for a way to put these config settings into source control and have them automatically populate / deploy for different builds and environments.
namespace CombinedPortal.WcfClient {
public class FrameworkServiceProxy : IFrameworkService
{
private IFrameworkService _proxy;
public FrameworkServiceProxy()
{
var endpoint = new EndpointAddress("http://server:1234/FrameworkService.svc");
var binding = new WSHttpBinding(SecurityMode.None);
_proxy = new ChannelFactory<IFrameworkService>(binding, endpoint).CreateChannel();
}
public Framework GetCurrentFramework(double uniqueLearnerNumber)
{
var fw = _proxy.GetCurrentFramework(uniqueLearnerNumber);
return fw;
}
} }
Your code is C# code which executes on the server.
When then user presses a button on a web part there is a POST back to the Sharepoint web server, where the C# code executes.
It is therefore the web.config of your SharePoint site which is used.
I'm using WCF 4 on IIS 7.5 and want to eliminate the default .svc extension from the URL of all my RESTful services. I've seen the approaches documented using the Url Rewrite Module and an IHttpModule but I don't want to take those approaches.
I am vaguely familiar with the concept of Routes introduced in ASP.NET MVC and as I understand they are now abstracted out of MVC in Net 4 as System.Web.Routing. But in looking at the docs it appears I need to add a Global.asax file to my project which I'm not really keen on. Is there any other way to handle this?
I've also seen the Configuration-Based activation feature, but that only seems to eliminate the .svc file, but still requires I use .svc in the url of my service.
Can anyone summarize my options here for not needing .svc in my urls?
Sure, no problem: first off, read all about the new WCF 4 features in A Developer's Introduction to Windows Communication Foundation 4.
What you're looking for is called file-less service activation. It's a new setting in your <system.serviceModel> that looks something like this:
<serviceHostingEnvironment>
<serviceActivations>
<add factory="System.ServiceModel.Activation.ServiceHostFactory"
relativeAddress="[subfolder/]filename.svc" or "~/[subfolder/]filename.svc"
service="SomeNamespace.YourService"/>
</serviceActivations>
</serviceHostingEnvironment>
Basically, all the information you'd have in the *.svc file (path, service to call) is in this config section now.
You should be able to call this service at
http://yourserver/virtualdirectory/YourService
now - no more *.svc, no messy URL rewriting etc. - it just plain works!
Update: it doesn't seem to work that well, unless you go in and add a *.svc extension to your relative path - kind defeats the whole purpose!
If you want to register using an ASP.NET route, check out the MSDN docs on that topic. You'd have to have something like this in your application startup, in a web app that would be global.asax.cs:
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private void RegisterRoutes(RouteCollection routes)
{
routes.Add(new ServiceRoute("YourService",
new WebServiceHostFactory(), typeof(SomeNamespace.YourService)));
}
Hopefully, with that, you'll be able to get your service up and running without any *.svc file extensions!
Just to wrap up the answer and add one more point there. You'll need the same ASP.NET route registration as above:
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private void RegisterRoutes(RouteCollection routes)
{
routes.Add(new ServiceRoute("YourService",
new WebServiceHostFactory(), typeof(SomeNamespace.YourService)));
}
In order to get this working you need however to add some more things to web.config. The service hosting should be configured to be ASP.NET compatible. This can be done by adding aspNetCompatibiliyEnabled="true" to serviceHostingEnvironment element:
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
Hope this clarifies and gives an easier to find solution.
Important clarification for IIS 7.5 and Framework 4.0:
For the Web routing module to work, it requires the application pool set to "Integrated Mode", it doesn't works in "Classic Mode"
One additional problem I've found after switching is that when in "Integrated Mode" the application crashed on startup because I had modules included in the <system.Web> section.
I fixed it by moving the modules to the <system.webServer> configuration section that is new for IIS 7