So I know how to implement this in previous versions of .NET Core. But I am having trouble doing it for .NET Core 6.
In .Net 3.1 or 5, from the documentation, it is done as follows:
Install the nuget package: "Install-Package DNTCaptcha.Core"
In the _ViewImports.cshtml file add #addTagHelper *, DNTCaptcha.Core
Use the helper tag in the form <dnt-captcha asp-captcha-generator-max="9000" //code// />
Register the default providers services.AddDNTCaptcha(); in the Startup class.
Include jQuery, font awesome, and jquery.unobtrusive-ajax
And in controller, ValidateDNTCaptcha attribute to your action method
This works well. But with .NET Core 6, there is no Startup class. So how do I register the default providers? I tried doing it this way in the Program class:
builder.Services.AddDNTCaptcha(options =>
options.UseCookieStorageProvider()
.ShowThousandsSeparators(false)
);
But this gave me the error:
InvalidOperationException: Please set the `options.WithEncryptionKey(...)`.
I tried looking at other sources and documentation but they all make use of the Startup class. So how can I implement this in .NET Core 6?
Do it this way:
IWebHostEnvironment _env = builder.Environment;
builder.services.AddDNTCaptcha(options =>
{
// options.UseSessionStorageProvider() // -> It doesn't rely on the server or client's times. Also it's the safest one.
// options.UseMemoryCacheStorageProvider() // -> It relies on the server's times. It's safer than the CookieStorageProvider.
options.UseCookieStorageProvider(SameSiteMode.Strict /* If you are using CORS, set it to `None` */) // -> It relies on the server and client's times. It's ideal for scalability, because it doesn't save anything in the server's memory.
// .UseDistributedCacheStorageProvider() // --> It's ideal for scalability using `services.AddStackExchangeRedisCache()` for instance.
// .UseDistributedSerializationProvider()
// Don't set this line (remove it) to use the installed system's fonts (FontName = "Tahoma").
// Or if you want to use a custom font, make sure that font is present in the wwwroot/fonts folder and also use a good and complete font!
.UseCustomFont(Path.Combine(_env.WebRootPath, "fonts", "IRANSans(FaNum)_Bold.ttf"))
.AbsoluteExpiration(minutes: 7)
.ShowThousandsSeparators(false)
.WithNoise(pixelsDensity: 25, linesCount: 3)
.WithEncryptionKey("This is my secure key!")
.InputNames(// This is optional. Change it if you don't like the default names.
new DNTCaptchaComponent
{
CaptchaHiddenInputName = "DNT_CaptchaText",
CaptchaHiddenTokenName = "DNT_CaptchaToken",
CaptchaInputName = "DNT_CaptchaInputText"
})
.Identifier("dnt_Captcha")// This is optional. Change it if you don't like its default name.
;
});
Related
This question already has answers here:
Remove "Server" header from ASP.NET Core 2.1 application
(7 answers)
Closed last month.
I have a .net 6.0 C# API (developed on a Mac using Kestrel server) that is returning server in the response header. All the solutions I have tried for are for pre-6 and are no longer relevant.
I have tried this in my Program.cs:
app.Use((ctx, next) => {
var headers = ctx.Response.Headers;
headers.Add("X-Frame-Options", "DENY");
headers.Add("X-XSS-Protection", "1; mode=block");
headers.Add("X-Content-Type-Options", "nosniff");
headers.Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
headers.Remove("Server");
return next();
});
This does not remove server, but it is adding the other headers. If I add the Server property with blanks (e.g. headers.Add("Server", ""); ) then the server name (Kestrel) is not shown, but the header property still appears. This probably achieves the objective, but I would rather it not appear at all.
ChatGPT (I know, but I tried it as a last resort), suggested
var host = new WebHostBuilder().UseKestrel(options => options.AddServerHeader = false).UseStartup<StartupBase>().Build();
but that gave a run time error Cannot instantiate implementation type 'Microsoft.AspNetCore.Hosting.StartupBase' for service type 'Microsoft.AspNetCore.Hosting.IStartup'..
As a lesser important side question, since removing Server is best practice, I wonder why the default functionality is to include it rather than omit it. Shouldn't the onus be to add it in? What would a use case for including that value be?
The correct syntax to use is:
builder.WebHost.UseKestrel(option => option.AddServerHeader = false);
The builder variable is available in the default template generated by Visual Studio.
In the default template, it is generated as:
var builder = WebApplication.CreateBuilder(args);
where args is the parameters passed to the Main method. The builder is then later used to generate the app. Make sure to set the Kestrel options before the call to Build that generates the app.
Documentation for the KestrelServerOptions.AddServerHeader property is available online.
I'm currently working on integrated Cors within a .Net Core app. I have previously dealt with Cors within the full .NET Framework (4.6.1) which had the ability to set the AllowAnyOrigin property within a given CorsPolicy.
Like mentioned before, I have written a .NET Core WebApi, which I am trying to implement Cors into. I have it reading from an AppSetting stored in my appSettings.json, from which it can be either three things:
If the appsetting is set to an asterisk, then I would like to see the AllowAnyOrigin property like I have done in the full .NET framework. (This is where my problem lies.)
If the appsetting is set to a comma seperated string, such as https://example.com, https://test.com, then this is applied onto the policy as needed.
If the appsetting has been commented out or left as empty, then I am reading a list of rows from Azure Table Storage to supply a list of given origins.
Below is an example of the full .NET framework that I have dealt with before.
var origins = ConfigurationManager.AppSettings[KeyCorsAllowOrigin];
switch (origins)
{
case null:
_corsPolicy.Origins.Clear();
foreach (var item in new StorageConfigurationManager().GetRowKeys())
{
_corsPolicy.Origins.Add("https://" + item);
}
break;
case "*":
_corsPolicy.AllowAnyOrigin = true;
break;
default:
_corsPolicy.AllowAnyOrigin = false;
if (!string.IsNullOrWhiteSpace(origins)) AddCommaSeparatedValuesToCollection(origins, _corsPolicy.Origins);
break;
}
I thought that I could replicate this functionality within .NET Core and the Microsoft.AspNetCore.Cors.Infrastructure package, but it seems that Microsoft has restricted access to setting the property, and can only be read from.
Does anyone know of any way to set this?
I know you can build the CorsPolicy within the pipeline, which then uses the .AllowAnyOrigin(), but I am currently using custom Cors middleware to help with my custom policy.
There is a great article called Enabling CORS in ASP.NET Core I'll sum the interesting part for you:
to only allow GET methods on your resource, you can use the WithMethods method when you define the CORS policy:
services.AddCors(options =>
{
options.AddPolicy("AllowOrigin",
builder => builder.WithOrigins("http://localhost:55294")
.WithMethods("GET"));
});
If you need to allow any origin to access the resource, you will use AllowAnyOrigin instead of WithOrigins:
services.AddCors(options =>
{
options.AddPolicy("AllowOrigin",
builder => builder.AllowAnyOrigin());
});
Just as an answer to all this, and so that perhaps someone can be helped by this question. I looked at the source code for the AllowAnyOrigin method within the CorsPolicyBuilder class and saw how this was handled. I nearly had the solution, just forgot to clear the Origins list beforehand.
_policy.Origins.Clear();
_policy.Origins.Add(CorsConstants.AnyOrigin);
Currently I Have configured Identityserver4 as separated project + My WebAPI and store in DB Credentials in IdentityServer.
Now i have problem how to make CRUD(In my frontend API) to IdentityServer(I want from my API add Clients to IdentityServer)
How to make property?
From IdentityServer4.EntityFramework and IdentityServer4.EntityFramework.Storage, you have access to IConfigurationDbContext (once you've added the required services in ConfigureServices using e.g. AddConfigurationStore). Because this is registered as part of the Dependency Injection system, you can take a dependency on it in one of your controllers. e.g.:
public class ClientsController : ControllerBase
{
private readonly IConfigurationDbContext _configurationDbContext;
public ClientsController(IConfigurationDbContext configurationDbContext)
{
_configurationDbContext = configurationDbContext;
}
// ...
}
IConfigurationDbContext is an abstraction of a standard DbContext, with the following DbSet<T> properties:
Clients
IdentityResources
ApiResources
It also includes both SaveChanges and SaveChangesAsync - Everything one might expect from a DbContext. Because of all of this, you can CRUD each of these entities just like any other Entity Framework Core driven database.
One final thing to note is that there are both Models (in IdentityServer4.Storage) and Entities (in IdentityServer4.EntityFramework.Storage). There are also a few extension methods for mapping between these (e.g. ClientMappers.ToEntity).
Given all of this, you can create a Model inside of your controller (or perhaps somewhere much better encapsulated than directly there). Here's a basic example for creating a new Client:
var clientModel = new Client
{
ClientId = "",
ClientName = "",
// ...
};
_configurationDbContext.Clients.Add(clientModel.ToEntity());
await _configurationDbContext.SaveChangesAsync();
The Client class here comes from IdentityServer4.Models and is then converted to an Entity using a ToEntity extension method I hinted at above. Working with a Model and converting to an Entity is simpler than trying to manipulate an Entity directly - If you're interested, you can see the mapping that takes place here.
This works in the same way for ApiResources, IdentityResources, etc. Use the source code links I've provided if you want to find out more about those specifically, but the information I've provided here should have you covered.
In order to use IdentityServer4 and IdentityServer4.EntityFramework in your API project, you can just add the two references to your API project. After that, you can configure the DI in the same way (using AddIdentityServer in ConfigureServices), but you don't need to add the middleware (using UseIdentityServer in Configure). You can even just use AddIdentityServer().AddConfigurationStore(...) to set up the relevant services, as you don't need a signing key, etc.
One way you can do this is by bootstrapping the ID4 Quickstart (tutorial located here):
http://docs.identityserver.io/en/release/quickstarts/3_interactive_login.html
Other option is to use their quickstart seeds located here to speed this up:
https://github.com/IdentityServer/IdentityServer4.Samples
Now if you want to implement restfull login there are constraints around it (i wanted to find out as well) check out this question:
IdentityServer 4 Restfull Login/Logout
I am trying to consume OData from a windows forms. So, what i have done to now is create a new project, i added a web service reference to the OData service and try to consume it.
My code is:
var VistaEntities = new VrExternalEntities("serviceURI");
var query = VistaEntities.VRtblCinemaType
.Where(
x =>
x.VRtblCinema_Operators
.Any
(
z =>
z.VRtblSessions
.Any
(
y =>
y.Session_dtmDate_Time > DateTime.Now
)
)
)
.Select
(
x =>
new
{
x.CinType_strCode,
x.CinType_strDescription
}
);
If i remove the Where clause it works. If i do it says that Any is not supported. I know i have to set MaxProtocolVersion to V3 but i do not know how to do it. I don't have an entity context or anything else. I only have what i have stated above.
Please provide steps on how to accomplish that.
Thanks in advance.
Giannis
You must retrieve the configuration of your DataService and set the MaxProtocolVersion of its behavior to V3.
The best place to do this is certainly in the InitializeService static method you can define in your service class, which will be given the proper configuration object as its config parameter by the environment. It will only be invoked once, typically at the first request.
Note #1: You need WCF Data Services 5.0 or greater. The best way to get it is probably via the Server NuGet package.
Note #2: Oddly enough, the DataServiceProtocolVersion type, although in the Common namespace, is included in the Client assembly (Microsoft.Data.Services.Client, provided by the Client NuGet package). I suggested a better organization here.
public class Vista : DataService<VistaContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule(...);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
...
}
}
Update:
The client may indeed specify the desired version in the requests by using the DataServiceVersion HTTP header. It's currently recommended that you specify and support a range of versions using the MinDataServiceVersion and MaxDataServiceVersion headers if you can, for obvious reasons. Note however that the MinDataServiceVersion will be removed in OData 4.0 (see appendix E.1 of part 1 and "What's new" documents drafts).
The relevant documentation for the WCF Data Services 5.x implementation is available here. The documentation specific to the client seems pretty scarce, but looking at the reference you can see that you must use this constructor for the DataServiceContext to specify the maximum protocol version, and it looks like you cannot change it at any one point for subsequent requests without rebuilding a new context. You may attempt to fiddle with the headers directly, but I wouldn't expect it to work reliably (or at all).
So, to answer your question, you really need control over how you create the context for the client.
We are working on a legacy C# enterprise app. Its client uses several web services, whose URLs, among lots of other settings, are read from the local app.config file. We want to migrate these settings into a global DB to simplify their management. However, I can't figure out how (and whether) it is possible to migrate the web service URLs. These are read from the service client code generated by VS and I can't seem to find a way to tell VS to use a different settings provider than the one generated into Settings.Designer.cs .
We can overwrite the service facade's Url property with the value we want, after it is created - this is the solution currently used in several places in the code. However, I wouldn't like to touch every part of our codebase where any of these services is used (now and in the future). Even less would I like to modify generated code.
There has to be a better, cleaner, safer solution - or is there?
Btw our app runs on .NET 2.0 and we won't migrate to newer versions of the platform in the foreseeable future.
The Refernce.cs file that is generated by the Visual Studio indicates that the URL of the webservice will be retrieved from the settings:
this.Url = global::ConsoleApplication1.Properties.
Settings.Default.ConsoleApplication1_net_webservicex_www_BarCode;
I believe that John Saunders gave you a wonderful suggestion in his comment. You need a SettingsProvider class which:
...defines the mechanism for storing configuration data used in the
application settings architecture. The .NET Framework contains a
single default settings provider, LocalFileSettingsProvider, which
stores configuration data to the local file system. However, you can
create alternate storage mechanisms by deriving from the abstract
SettingsProvider class. The provider that a wrapper class uses is
determined by decorating the wrapper class with the
SettingsProviderAttribute. If this attribute is not provided, the
default, LocalFileSettingsProvider, is used.
I don't know how much you have progressed following this approach, but it should go pretty straighforward:
Create the SettingsProvider class:
namespace MySettings.Providers
{
Dictionary<string, object> _mySettings;
class MySettingsProvider : SettingsProvider
{
// Implement the constructor, override Name, Initialize,
// ApplicationName, SetPropertyValues and GetPropertyValues (see step 3 below)
//
// In the constructor, you probably might want to initialize the _mySettings
// dictionary and load the custom configuration into it.
// Probably you don't want make calls to the database each time
// you want to read a setting's value
}
}
Extend the class definition for the project's YourProjectName.Properties.Settings partial class and decorate it with the SettingsProviderAttribute:
[System.Configuration.SettingsProvider(typeof(MySettings.Providers.MySettingsProvider))]
internal sealed partial class Settings
{
//
}
In the overridden GetPropertyValues method, you have to get the mapped value from the _mySettings dictionary:
public override SettingsPropertyValueCollection GetPropertyValues(
SettingsContext context,
SettingsPropertyCollection collection)
{
var spvc = new SettingsPropertyValueCollection();
foreach (SettingsProperty item in collection)
{
var sp = new SettingsProperty(item);
var spv = new SettingsPropertyValue(item);
spv.SerializedValue = _mySettings[item.Name];
spv.PropertyValue = _mySettings[item.Name];
spvc.Add(spv);
}
return spvc;
}
As you can see in the code, in order to do that, you need to know the setting name as it was added in the app.config and the Settings.settings when you have added the reference to the web service (ConsoleApplication1_net_webservicex_www_BarCode):
<applicationSettings>
<ConsoleApplication30.Properties.Settings>
<setting name="ConsoleApplication1_net_webservicex_www_BarCode"
serializeAs="String">
<value>http://www.webservicex.net/genericbarcode.asmx</value>
</setting>
</ConsoleApplication30.Properties.Settings>
</applicationSettings>
This is a very simple example, but you might use a more complex object to store the configuration information in conjunction with other properties available in the context such as item.Attributes or context in order to get the proper configuration value.