Here is the c# code:
var server = ******* some internal logic to determine server name ****
var username = ******* some internal logic to determine user name ****
var password = ******* some internal logic to determine password ****
ObjectFactory.Initialize(x =>
{
x.For<IService<bool>>().Add<Service>()
.Ctor<string>("server").Is(server)
.Ctor<string>("username").Is(username)
.Ctor<string>("password").Is(password)
}
This works great but I would like to move this to configuration file as I don't want to reference to concerete type directly in my code.
There isn't much documentation about 2.6. I couldn't find how to handle this in configuration.
Ideally I would like to inject the server, username, and password paramenters in to ObjectFactory and some how use these parameters in the configuration.
(PS: It doesn't necessary need to be with StructureMap any IAC container that can support this scenario will be welcome.)
Thanks
The simplest way to handle this type of case would be to introduce a new type to provide the primitive constructor args, and register that in code. Then you can register the service, and that new type can be auto wired by the container. This also allows you to move the logic to get the server, username and password into this new object and out of the container configuration.
Related
What's the best way to know if my app is running under Kestrel or HTTP.sys. All that I have found so far is to check for "Kestrel" in one of the HttpConext property class names.
Within an MVC controller I can do something like this:
Boolean IsKestrel = HttpContext.Features.GetType().ToString().Contains("Kestrel");
i.e. check this:
Features = {Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection<Microsoft.AspNetCore.Hosting.HostingApplication.Context>}
When using HTTP.sys I only get:
Features = {Microsoft.AspNetCore.Http.Features.FeatureCollection}
(Is "Http" here enough to know that this is HTTP.sys?)
There must be a better way. Is there an obvious property somewhere that contains the name of the host being used?
A broader question might be, how do I know what the builder pattern built?
Update
Found something better, but still looking for a Property that has the server name or type.
In an MVC controller:
var isKestrel = HttpContext.Request.Headers.GetType().ToString().Contains(".Kestrel.");
var isHTTPsys = HttpContext.Request.Headers.GetType().ToString().Contains(".HttpSys.");
At the operating system level, netsh http show servicestate will list all active URLs listening via HTTP.SYS.
From code you can locate an instance of Microsoft.AspNetCore.Hosting.Server.IServer and check what its implementation is, in netcore 6:
Kestrel => Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl
IIS ==> Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer
HTTP.SYS => Microsoft.AspNetCore.Server.HttpSys.MessagePump
This relies on implementation details (so can break), also other extensions can change these e.g. CoreWcf creates CoreWCF.Configuration.WrappingIServer that wraps one of the above implementations.
you can use System.Diagnostics.Process.GetCurrentProcess().ProcessName
I am not sure whether you want to check this information using the code only or you are just looking for a way to know on which web server your app is running.
In my search result, I found that we could set the ports for a specific web server. When the application will run on that specific web server then it will use that pre-configured port. I am assuming your app also has a similar configuration. You could set the different ports for Kestrel, Http.sys, or IIS. By checking the port number you could say that on which web server your site is running.
You could try to go to the launchSettings.json file in your project where you could configure ports for IIS and Kestral.
Helpful References:
Kestrel Web Server in ASP.NET Core
Understand HTTP.sys Web Server In ASP.NET Core
Hello this is a good question, you question is asking how to find out from inside the code and not from a console.
OOB I did not find anything. So, I had to get very creative to figure this out, sorry for the typo's its brand new stuff...
Option 1:
Since the Kestrel section & endpoints are inside the appsettings.json I used that to find out if its hosted by Kestrel!
//Please create a static class to hold the config.
public static class MyStartupIsItKestrelConfiguration
{
public static IConfiguration Configuration;
public bool static IsKestrel()
{
//check your section kestrel??
var kestrel = configuration.GetSection("Kestrel");
// now check kestrel section or any other section
// see picture for kestrel endpoint in app setting sbelow
return true;
}
}
Now you can access it anywhere and see if you used Kestrel
//Now add it/save it in your startup and access later
public Startup(IConfiguration configuration)
{
Configuration = configuration;
MyStartupIsItKestrelConfiguration.Configuration = configuration;
}
Once you have this
//you can use it in ** YOUR CONTROLLER
MyStartupIsItKestrelConfiguration.IsKestrel();
Option 2:
Please check this public Microsoft.AspNetCore.Http.Features.IFeatureCollection Features { get; }
You can get the features public TFeature? Get<TFeature> (); as a Key Value Pair - and then check the feature for e.g. KESTREL DOES NOT ALLOW PORT SHARING
they split the features namespace in .net core 6 there are breaking changes
You should use the features collection
My ASP.NET MVC application uses Dependency Injection to inject services to the controllers.
I need to find some way of passing run-time data to the services, because as far as I know it's anti-pattern to send run-time data to the constructors using DI.
In my case I have four different services that all rely on access tokens, which can be re-used between the services. However, that access token can expire so something needs to take care of issuing new access token when it expires.
The services (independent NuGet packages) are all clients for various services, that require access token for every request made. One example would be the AddUserAsync method in the IUserServiceBusiness, it basically POSTs to an endpoint with JSON data and adds Authorization header with bearer access token.
My current solution is to accept access token as a parameter in all of the methods in the services, which means that the web application takes care of handling the access tokens and passing them when needed.
But this solution smells, there has to be a better way of doing this.
Here's an example on how it's done currently.
The RegisterContainer method where all of the implementations are registered.
public static void RegisterContainers()
{
// Create a new Simple Injector container
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
SSOSettings ssoSettings = new SSOSettings(
new Uri(ConfigConstants.SSO.FrontendService),
ConfigConstants.SSO.CallbackUrl,
ConfigConstants.SSO.ClientId,
ConfigConstants.SSO.ClientSecret,
ConfigConstants.SSO.ScopesService);
UserSettings userSettings = new UserSettings(
new Uri(ConfigConstants.UserService.Url));
ICacheManager<object> cacheManager = CacheFactory.Build<object>(settings => settings.WithSystemRuntimeCacheHandle());
container.Register<IUserBusiness>(() => new UserServiceBusiness(userSettings));
container.Register<IAccessTokenBusiness>(() => new AccessTokenBusiness(ssoSettings, cacheManager));
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcIntegratedFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
Implementation of IUserBusiness and IAccessTokenBusiness are injected to AccountController.
private readonly IUserBusiness _userBusiness;
private readonly IAccessTokenBusiness _accessTokenBusiness;
public AccountController(IUserBusiness userBusiness, IAccessTokenBusiness accessTokenBusiness)
{
_userBusiness = userBusiness;
_accessTokenBusiness = accessTokenBusiness;
}
Example endpoint in AccountController that updates the user's age:
public ActionResult UpdateUserAge(int age)
{
// Get accessToken from the Single Sign On service
string accessToken = _accessTokenBusiness.GetSSOAccessToken();
bool ageUpdated = _userBusiness.UpdateAge(age, accessToken);
return View(ageUpdated);
}
And here are some ideas that I've thought of:
Pass the access token to the services with a setter, in the constructor of the controllers. For example:
public HomeController(IUserBusiness userBusiness, IAccessTokenBusiness accessTokenBusiness)
{
_userBusiness = userBusiness;
_accessTokenBusiness = accessTokenBusiness;
string accessToken = _accessTokenBusiness.GetAccessToken();
_userBusiness.setAccessToken(accessToken);
}
I donĀ“t like this idea because then I would have to duplicate this code in every controller.
Pass the access token with every method on the services (currently doing this). For example:
public ActionResult UpdateUser(int newAge)
{
string accessToken = _accessTokenBusiness.GetAccessToken();
_userBusiness.UpdateAge(newAge, accessToken);
}
Works, but I don't like it.
Pass implementation of IAccessTokenBusiness to the constructor of the services. For example:
IAccessTokenBusiness accessTokenBusiness = new AccessTokenBusiness();
container.Register<IUserBusiness>(() => new IUserBusiness(accessTokenBusiness));
But I'm unsure how I would handle caching for the access tokens. Perhaps I can have the constructor of AccessTokenBusiness accept some generic ICache implementation, so that I'm not stuck with one caching framework.
I would love to hear how this could be solved in a clean and clever way.
Thanks!
As I see it, the requirement of having this access token for communication with external services is an implementation detail to the class that actually is responsible of calling that service. In your current solution you are leaking these implementation details, since the IUserBusiness abstraction exposes that token. This is a violation of the Dependency Inversion Principle that states:
Abstractions should not depend on details.
In case you ever change this IUserBusiness implementation to one that doesn't require an access token, it would mean you will have to make sweeping changes through your code base, which basically means you voilated the Open/close Principle.
The solution is to let the IUserBusiness implementation take the dependency on IAccessTokenBusiness itself. This means your code would look as follows:
// HomeController:
public HomeController(IUserBusiness userBusiness)
{
_userBusiness = userBusiness;
}
public ActionResult UpdateUser(int newAge)
{
bool ageUpdated = _userBusiness.UpdateAge(newAge);
return View(ageUpdated);
}
// UserBusiness
public UserBusiness(IAccessTokenBusiness accessTokenBusiness)
{
_accessTokenBusiness = accessTokenBusiness;
}
public bool UpdateAge(int age)
{
// Get accessToken from the Single Sign On service
string accessToken = _accessTokenBusiness.GetSSOAccessToken();
// Call external service using the access token
}
But I'm unsure how I would handle caching for the access tokens.
This is neither a concern of the controller nor the business logic. This is either a concern of the AccessTokenBusiness implementation or a decorator around IAccessTokenBusiness. Having a decorator is the most obvious solution, since that allows you to change caching independently of generation of access tokens.
Do note that you can simplify your configuration a bit by making use of the container's auto-wiring abilities. Instead of registering your classes using a delegate, you can let the container analyse the type's constructor and find out itself what to inject. Such registration looks as follows:
container.Register<IUserBusiness, UserServiceBusiness>();
container.Register<IAccessTokenBusiness, AccessTokenBusiness>();
ICacheManager<object> cacheManager =
CacheFactory.Build<object>(settings => settings.WithSystemRuntimeCacheHandle());
container.RegisterSingleton<ICacheManager<object>>(cacheManager);
Further more, a decorator for IAccessTokenBusiness can be added as follows:
container.RegisterDecorator<IAccessTokenBusiness, CachingAccessTokenBusinessDecorator>();
I am trying to build a multilayer application (service) in C#. To be precise, I am trying to build a REST webservice with ASP.NET Web Api which will be hosted on my own (with Owin). Now I got so far that I have the following components(every one of them is in a separate .dll):
- RestHost (which in my case is an console application)
- RestService (here is my web service witch all the controllers)
- InterfacesLayer
- ModelLayer (here are the objects I use, just with their get/set methods)
- DataLayer (every single class inside of ModelLayer has its own class in Datalayer, plus there is the Database connection class)
- BusinessLayer (here all the logic is done, again every class from model has its own class, and this layer communicates with the REST service and the datalayer).
RestHost - as the name says, it is the host of my service. Besides that I am also doing my dependency injection here. Since it is not much code I will post it:
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
// Dependency Resolving
container.RegisterType<IAktData, AktDataImpl>(new HierarchicalLifetimeManager());
container.RegisterType<IAktService, AktServiceImpl>(new HierarchicalLifetimeManager());
container.RegisterType<ILeistungData, LeistungDataImpl>(new HierarchicalLifetimeManager());
container.RegisterType<ILeistungService, LeistungServiceImpl>(new HierarchicalLifetimeManager());
container.RegisterType<IPersonData, PersonDataImpl>(new HierarchicalLifetimeManager());
container.RegisterType<IPersonService, PersonServiceImpl>(new HierarchicalLifetimeManager());
container.RegisterType<IPersistent, FirebirdDB>(new HierarchicalLifetimeManager());
string serverAddress = ConfigurationManager.AppSettings["serverAddress"];
string connectionString = ConfigurationManager.ConnectionStrings["connectionStrings"].ConnectionString;
using (RESTService.StartServer(container, serverAddress,connectionString ))
{
Console.WriteLine("Server started # "+ DateTime.Now.ToString() + " on " + serverAddress + "/api");
Console.ReadLine();
}
}
Oh and what I forgot to mention, but you can see it from the code, in my host application I am also reading the App.Config where my connection string is hosted.
And here is my problem. I am not sure how to access the Database Connection from my service. Here I am implementing Firebird in my data access layer, but I am unsure how to use it in my application. Of course the easiest way would be just to create an instance and pass it to my service but this is the last thing i want to do. I have also been thinking implementing Firebird as a static class or as a singleton, but then i cannot use my IPersistant interface (and besides that, i don't think that this is the right approach).
So my question would be, is there any best practice for this kind of stuff? I somehow need to pass the connectionstring to the implementation of IPersistent (Firebird) but without actually creating an instance of Firebird in my RESTService.
Thanks
The general pattern for a multi-layer application like the one you're building is to have a data layer that provides your services with access to a database, or some other method of persisting data, usually via a repository.
You can then configure your IoC container to inject your connection string into your repository and then inject your repository into your service. This way your service stays agnostic as to how data is persisted and can focus on defining the business logic.
I actually do a similar thing for a repository that instead of persisting data in a database, stores it in a blob on Azure's CDN. The configuration withing my IoC (StructureMap in my case) looks like this:
string storageApiKey = ConfigurationManager.AppSettings["CloudStorageApiKey"];
string storageUsername = ConfigurationManager.AppSettings["CloudStorageUsername"];
this.For<IImageStorageRepository>().Use<ImageStorageRepository>().Ctor<string>("storageApiKey").Is(storageApiKey).Ctor<string>("storageUsername").Is(storageUsername);
With my repository looking like this:
public class ImageStorageRepository : IImageStorageRepository
{
....
public ImageStorageRepository(string storageApiKey, string storageUsername)
{
this.cloudIdentity = new CloudIdentity() { APIKey = storageApiKey, Username = storageUsername };
this.cloudFilesProvider = new CloudFilesProvider(cloudIdentity);
}
....
}
I have a form:
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary()...
and action:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl, string City)
{
}
occasionally (once a week), I get the error:
The anti-forgery token could not be decrypted. If this application is
hosted by a Web Farm or cluster, ensure that all machines are running
the same version of ASP.NET Web Pages and that the configuration
specifies explicit encryption and validation keys. AutoGenerate cannot
be used in a cluster.
i try add to webconfig:
<machineKey validationKey="AutoGenerate,IsolateApps"
decryptionKey="AutoGenerate,IsolateApps" />
but the error still appears occasionally
I noticed this error occurs, for example when a person came from one computer and then trying another computer
Or sometimes an auto value set with incorrect data type like bool to integer to the form field by any jQuery code please also check it.
I just received this error as well and, in my case, it was caused by the anti-forgery token being applied twice in the same form. The second instance was coming from a partial view so wasn't immediately obvious.
validationKey="AutoGenerate"
This tells ASP.NET to generate a new encryption key for use in encrypting things like authentication tickets and antiforgery tokens every time the application starts up. If you received a request that used a different key (prior to a restart for instance) to encrypt items of the request (e.g. authenication cookies) that this exception can occur.
If you move away from "AutoGenerate" and specify it (the encryption key) specifically, requests that depend on that key to be decrypted correctly and validation will work from app restart to restart. For example:
<machineKey
validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D7
AD972A119482D15A4127461DB1DC347C1A63AE5F1CCFAACFF1B72A7F0A281B"
decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F"
validation="SHA1"
decryption="AES"
/>
You can read to your heart's content at MSDN page: How To: Configure MachineKey in ASP.NET
Just generate <machineKey .../> tag from a link for your framework version and insert into <system.web><system.web/> in Web.config if it does not exist.
Hope this helps.
If you get here from google for your own developer machine showing this error, try to clear cookies in the browser. Clear Browser cookies worked for me.
in asp.net Core you should set Data Protection system.I test in Asp.Net Core 2.1 or higher.
there are multi way to do this and you can find more information at Configure Data Protection and Replace the ASP.NET machineKey in ASP.NET Core and key storage providers.
first way: Local file (easy implementation)
startup.cs content:
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
{
Configuration = configuration;
WebHostEnvironment = webHostEnvironment;
}
public IConfiguration Configuration { get; }
public IWebHostEnvironment WebHostEnvironment { get; }
// This method gets called by the runtime.
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// .... Add your services like :
// services.AddControllersWithViews();
// services.AddRazorPages();
// ----- finally Add this DataProtection -----
var keysFolder = Path.Combine(WebHostEnvironment.ContentRootPath, "temp-keys");
services.AddDataProtection()
.SetApplicationName("Your_Project_Name")
.PersistKeysToFileSystem(new DirectoryInfo(keysFolder))
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
}
}
second way: save to db
The Microsoft.AspNetCore.DataProtection.EntityFrameworkCore NuGet
package must be added to the project file
Add MyKeysConnection ConnectionString to your projects
ConnectionStrings in appsettings.json > ConnectionStrings >
MyKeysConnection.
Add MyKeysContext class to your project.
MyKeysContext.cs content:
public class MyKeysContext : DbContext, IDataProtectionKeyContext
{
// A recommended constructor overload when using EF Core
// with dependency injection.
public MyKeysContext(DbContextOptions<MyKeysContext> options)
: base(options) { }
// This maps to the table that stores keys.
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
}
startup.cs content:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime.
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// ----- Add this DataProtection -----
// Add a DbContext to store your Database Keys
services.AddDbContext<MyKeysContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyKeysConnection")));
// using Microsoft.AspNetCore.DataProtection;
services.AddDataProtection()
.PersistKeysToDbContext<MyKeysContext>();
// .... Add your services like :
// services.AddControllersWithViews();
// services.AddRazorPages();
}
}
If you use Kubernetes and have more than one pod for your app this will most likely cause the request validation to fail because the pod that generates the RequestValidationToken is not necessarily the pod that will validate the token when POSTing back to your application. The fix should be to configure your nginx-controller or whatever ingress resource you are using and tell it to load balance so that each client uses one pod for all communication.
Update: I managed to fix it by adding the following annotations to my ingress:
https://kubernetes.github.io/ingress-nginx/examples/affinity/cookie/
Name Description Values
nginx.ingress.kubernetes.io/affinity Sets the affinity type string (in NGINX only cookie is possible
nginx.ingress.kubernetes.io/session-cookie-name Name of the cookie that will be used string (default to INGRESSCOOKIE)
nginx.ingress.kubernetes.io/session-cookie-hash Type of hash that will be used in cookie value sha1/md5/index
I ran into this issue in an area of code where I had a view calling a partial view, however, instead of returning a partial view, I was returning a view.
I changed:
return View(index);
to
return PartialView(index);
in my control and that fixed my problem.
I got this error on .NET Core 2.1. I fixed it by adding the Data Protection service in Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection();
....
}
you are calling more than one the #Html.AntiForgeryToken() in your view
I get this error when the page is old ('stale'). A refresh of the token via a page reload resolves my problem. There seems to be some timeout period.
I found a very interesting workaround for this problem, at least in my case. My view was dynamically loading partial views with forms in a div using ajax, all within another form. the master form submits no problem, and one of the partials works but the other doesn't. The ONLY difference between the partial views was at the end of the one that was working was an empty script tag
<script type="text/javascript">
</script>
I removed it and sure enough I got the error. I added an empty script tag to the other partial view and dog gone it, it works! I know it's not the cleanest... but as far as speed and overhead goes...
I know I'm a little late to the party, but I wanted to add another possible solution to this issue. I ran into the same problem on an MVC application I had. The code did not change for the better part of a year and all of the sudden we started receiving these kinds of error messages from the application.
We didn't have multiple instances of the anti-forgery token being applied to the view twice.
We had the machine key set at the global level to Autogenerate because of STIG requirements.
It was exasperating until I got part of the answer here: https://stackoverflow.com/a/2207535/195350:
If your MachineKey is set to AutoGenerate, then your verification
tokens, etc won't survive an application restart - ASP.NET will
generate a new key when it starts up, and then won't be able to
decrypt the tokens correctly.
The issue was that the private memory limit of the application pool was being exceeded. This caused a recycle and, therefore, invalidated the keys for the tokens included in the form. Increasing the private memory limit for the application pool appears to have resolved the issue.
My fix for this was to get the cookie and token values like this:
AntiForgery.GetTokens(null, out var cookieToken, out var formToken);
For those getting this error on Google AppEngine or Google Cloud Run, you'll need to configure your ASP.NET Core website's Data Protection.
The documentation from the Google team is easy to follow and works.
https://cloud.google.com/appengine/docs/flexible/dotnet/application-security#aspnet_core_data_protection_provider
A general overview from the Microsoft docs can be found here:
https://cloud.google.com/appengine/docs/flexible/dotnet/application-security#aspnet_core_data_protection_provider
Note that you may also find you're having to login over and over, and other quirky stuff going on. This is all because Google Cloud doesn't do sticky sessions like Azure does and you're actually hitting different instances with each request.
Other errors logged, include:
Identity.Application was not authenticated. Failure message: Unprotect ticket failed
In my managed bean i need to access a mySql database.
So far i used code like this:
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test";
String username = "user";
String password = "1234";
Connection connection = null;
try {
connection = DriverManager.getConnection(url, username, password);
Now i have to do this in more than one bean, so if i need to change the database credentials, i have to fiddle around in like 10 files.
Is there
a way to store the databaseconnection
a way to define some variables for the whole web project
Thanks in advance
First of all you should understand basic architecture of a Java EE project. It is not a good idea connecting databases in managed beans. It is really bad practice. Please have look my previous answer to understand basic architecture.
Database connections is done in Integration Tier and these classes are called Data Access Objects (DAO).
Create a BaseDao class for static connection properties.
class BaseDao
{
private String url = "jdbc:mysql://localhost:3306/test";
private String username = "user";
private String password = "1234";
private Connection connection;
protected Connection getConnection()
{
connection = DriverManager.getConnection(url, username, password);
return connection;
}
}
and extend base class to its derived classes where database connection is needed and access connection by using BaseDao#getConnection().
Furthermore, it is better to keep database connections in a properties file and inject them into proper classes.
Related Tutorial
Read BalusC tutorial for better understanding DAO tutorial - the data layer
It is generally a good idea to store these kind of values in a .properties file. They can then be accessed via java.util.Properties (http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html)
Here is a good tutorial describing how access these files and their values, I suggest you start with this: http://www.mkyong.com/java/java-properties-file-examples/
(More information: http://en.wikipedia.org/wiki/.properties)
In my IDE, I usually create a new source package /src/main/config and put all my configuration-concerning .properties and .xml files in there. If you do it this way, you need to access it like this from within your jsf application:
String configFilePath = "configuration.properties";
props = new Properties();
InputStream propInStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(configFilePath);
props.load(propInStream);
Or you can simply do this:
How to get properties file from /WEB-INF folder in JSF?