Alternative to Cache Insert fuction in Net framework - asp.net-core

I am trying to set up this code https://stackoverflow.blog/2008/07/18/easy-background-tasks-in-aspnet/ (this code should be able to cyclically run some procedure on the same time - for example I need to update a database).
But I am currently using the ASP.NET Core 3.1 and there is no Insert function to the cache. I have managed other things around (for example other name of the delegate) but there is no chance with this issue.
Unfortunately I am still a begginer in C# so some things are still hard for me. I would appreciate any advice. Thank you a lot!

ASP.NET Core supports several different caches. The simplest cache (In-memory cache) is based on the IMemoryCache. By using the cache's Set method, you could create and add a new entry to the cache.
To use the Memory cache in asp.net core, you could refer the following steps:
First, register the MemoryCache in the ConfigureServices method of Startup class:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddMemoryCache();
}
Then, refer the following code to use it:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using System;
namespace MemoryCacheApplication.Controllers
{
public class HomeController : Controller
{
private readonly IMemoryCache memoryCache;
public HomeController(IMemoryCache memoryCache)
{
this.memoryCache = memoryCache;
}
}
public IActionResult Index()
{
DateTime currentTime;
bool isExist = memoryCache.TryGetValue("CacheTime", out currentTime);
if (!isExist)
{
currentTime = DateTime.Now;
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(30));
memoryCache.Set("CacheTime", currentTime, cacheEntryOptions);
}
return View(currentTime);
}
}
More detail information, please check the Cache in-memory in ASP.NET Core

Related

how and where to use/set collection in an asp.net core webapi?

I need record some temporary data of each client. I don't wish use database because I think collection is fast and these data don't need save for long time.
where I should set the collection? I don't know, in an asp.net core sever, how to make an collection class has a life cycle as long as the host, and can be visited by different controller?
You can use IMemoryCache.
ConfigureServices:
services.AddControllers();
Controller:
private IMemoryCache memoryCache;
public YourController(
IMemoryCache memoryCache)
{
this.memoryCache = memoryCache;
}
Access:
protected static string CacheKey = "UniqueCacheKey";
public static List<YourObject> GetCachedYourList(IMemoryCache cache)
{
if (cache.TryGetValue(CacheKey, out List<YourObject> cachedList))
{
return cachedList;
}
// otherwise populate your value from database
// var yourCachedList = ...
cache.Set(CacheKey, yourCachedList, TimeSpan.FromDays(14));
return yourCachedList;
}
For more details, check out the documentation:

How to access data from API in .Net Core

I've not worked with .Net Core before but have a lot of experience with MVC and Entity Framework. My project has four distinct folders, API, DTO, Repository and WEB. The DTO folder has many model files which fits the data model. The API folder has a Controller file called ReferenceDataController and looks like this
[Route("api/[controller]")]
[ApiController]
public class ReferenceDataController : ControllerBase
{
private readonly IReferenceDataRepository _repository;
public ReferenceDataController(IReferenceDataRepository repository)
{
_repository = repository;
}
// GET api/values
[HttpGet]
public ActionResult<ReferenceData> GetReferenceData()
{
return _repository.GetReferenceData();
}
I'm told that if I call this GET method it will return a data object. How do I call this method in the API folder from my HomeController in my WEB folder?
First, in your web project, you need to do a little setup. Add a class like the following:
public class ReferenceDataService
{
private readonly HttpClient _httpClient;
public ReferenceDataService(HttpClient httpClient)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}
public async Task<List<ReferenceData>> GetReferenceDataAsync(CancellationToken cancellationToken = default)
{
using (var response = await _httpClient.GetAsync("/api/referencedata", cancellationToken))
{
if (response.IsSuccessStatusCode())
{
return await response.Content.ReadAsAsync<List<ReferenceData>>();
}
return null;
}
}
}
Then, in ConfigureServices in Startup.cs:
services.AddHttpClient<ReferenceDataService>(c =>
{
c.BaseAddress = new Uri("https://api.example.com");
// Use the actual URL for your API here. You also probably want to get this
// from `Configuration` rather than hard-coding it.
});
Finally, inject ReferenceDataService into your HomeController:
public class HomeController : Controller
{
private readonly ReferenceDataService _referenceDataService;
public HomeController(ReferenceDataService referenceDataService)
{
_referenceDataService = referenceDataService ?? throw new ArgumentNullException(nameof(referenceDataService));
}
// In your action(s):
// var data = await _referenceDataService.GetReferenceDataAsync(HttpContext.RequestAborted);
}
This is the quick and dirty code here. Things you should consider for improvement:
Use an interface for your service class(es), i.e. IReferenceDataService. That will make testing easier. In ConfigureServices:
services.AddHttpClient<IReferenceDataService, ReferenceDataService>(...);
Then, inject IReferenceDataService instead.
You can and should use the Polly extensions with AddHttpClient to support retry and exception handling polices. At the very least, you'd definitely want to add AddTransientHttpErrorPolicy:
services.AddHttpClient<ReferenceDataService>(...)
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
}));
That will handle transient errors like temporarily being unable to connect to the API because it was restarted or something. You can find more info and more advanced configuration possibilities at the docs.
You should be using separate DTO classes. For brevity, I just used your (presumed) entity class ReferenceData. Instead, you should always use customized DTO classes that hold just the pieces of the data that you need to be available via the API. This way, you can control things like serialization as well as custom validation schemes, without conflicting with what's going on with your entity class. Additionally, the web project would only need to know about ReferenceDataDTO (or whatever), meaning you can share a library with your DTOs between the API and web projects and keep your DAL completely out of your web project.

No database provider has been configured for this DbContext .NET Core with SQL Server

I have been banging my head against a wall with this one and have been googling to no avail.
I have just started a new ASP.NET Core MVC project, I have installed/updated my packages for these two to 2.2.0:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
I have set the project to expect .NET Core 2.2.0 as well.
I am able to successfully add my table schemas with this command in Package Manager console to scaffold the Database, so I know the connection string is fine/working:
Scaffold-DbContext "SERVER=Server\Instance;DATABASE=Database;UID=user;PWD=password;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables Table1, Table2, Table3
The created model file, DatabaseDBContext.cs looks like this:
public partial class DatabaseDBContext : DbContext
{
public DatabaseDBContext()
{
}
public DatabaseDBContext(DbContextOptions<DatabaseDBContext> options)
: base(options)
{
}
}
This also contains a method that works to retrieve my scaffold data, but isn't considered safe for production use so I commented this out:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("SERVER=Server\\Instance;DATABASE=Database;UID=user;PWD=password;");
}
}
I added this same connection string to the appsettings.json file:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"DBConnString": "SERVER=Server\\Instance;DATABASE=Database;UID=user;PWD=password;"
}
}
I then added the DbContext to the startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddDbContext<DatabaseDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DBConnString")));
}
Trying to add a new scaffolded controller for one of the tables throws this error:
Finding the generator 'controller'...
Running the generator 'controller'...
Attempting to compile the application in memory.
Attempting to figure out the EntityFramework metadata for the model and DbContext: 'TableName'
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
StackTrace:
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)
at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure1 accessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func1 factory)
No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
Has anyone got any clue what I am doing wrong here?
So I fixed but it in a really roundabout way. My new project was originally on an older version of .net core. I had updated the version but there must have been something it didn't like during the update. I created a new project and started it on 2.2.0, then it worked...
The code logic was sound above. Still needed the same packages:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Startup.cs seems quite different, so maybe if anyone else sees this they could try updating the startup.cs code:
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)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<DatabaseDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DatabaseDBConnString")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
Had to add a reference to startup.cs for this:
using Microsoft.EntityFrameworkCore;
That was needed for the AddDbContext method to resolve.
After doing this the scaffolding now works. So it's fixed, but it required me to start over to fix it.
I had the same problem and this solved it for me (setting UseSqlServer in OnConfiguring):
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
if (!builder.IsConfigured)
{
string conn = this.IsProduction ? Const.ProductionConnectionString : Const.LocalDBConnectionString;
builder.UseSqlServer(conn);
}
base.OnConfiguring(builder);
}
After battleing with this issue I've encounter the solution for it here
https://github.com/aspnet/EntityFrameworkCore/issues/12331
The problem was that Add-Migration was expecting the CreateWebHostBuilder
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
Before my public static void Main(string[]) was running the WebHost without the static CreateWebHostBuilder and that after I added the Static function then it worked.
I had this problem after I've inlined Program.CreateWebHostBuilder into Program.Main. Had to extract it back.
It was wired but fixed this issue by updating the framework version of the project solution. For example, I created one core repo on 3.0 and later installed the latest version 3.1 on the system so it was expecting to be updated with the latest version. I changed it and it worked!
Try add this 3rd constructor:
public DatabaseDBContext()
{
}
public DatabaseDBContext(DbContextOptions<DatabaseDBContext> options)
: base(options)
{
}
public DatabaseDBContext(DbContextOptions options)
: base(options)
{
}
Then chuck a breakpoint in each one just so you are sure which one is actually getting used.

No parameterless constructor defined for this object in asp.netcore migrations

I am new to ASP.NET Core. learning new version of .NET Core 2.0 using VS Code. I got stuck while doing creating database using migration. First, it gives an exception of implementation of IDesignTimeDbContextFactory. After solving this, it still gives an exception of
No parameterless constructor defined for this object
Here's my code for DbContextClass:
public VegaDbContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<VegaDbContext>();
var connectionString =
configuration.GetConnectionString("DefaultConnection");
builder.UseSqlServer(connectionString);
return new VegaDbContext(builder.Options);
}
I had tried a couple of ways when I was experimenting with ef core. I faced similar issues too. Finally I found services working great. First you will need to create your DBContext with the following override constructor:
public VegaDbContext(DbContextOptions<VegaDbContext> options) : base(options)
{
}
In your start up, you can add your context as a service like this:
services.AddDbContext<ApplicationDBContext>(config => {
config.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
You can read in full detail about how dependency injection works here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
This part should help you with the migration. You can perform your migrations using the dotnet ef commands https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet.
When using your db context, do ensure that you are using dependency injection so you make full use of the AddDbContext function and keep it DRY.
https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro
If I were your in your shoes, I look at this document.
Here is the simple DbContext that you can find on this webSite
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
I just got the same error. If you are careful the error description is actually giving you the solution of the problem.
  DesignTimeFactoryObject's constructor function should not take parameters.
public class ExampleDesignTimeFactory : IDesignTimeDbContextFactory<YourDBContext>{
public ExampleDesignTimeFactory(){ no constructor or no parameter constructor }
}
I use ASP.NET CORE 3.1 to create the project and it solved

Get HttpContext in AspNet Core 1.0.0 outside a Controller

I need to get the HttpContext in AspNet Core outside a controller. In the older AspNet 4 I could get it using HttpContext.Current, but it seems to be removed in the new AspNet. The only workaround I have found is resolving an IHttpContextAccessor by dependency injection and asking it the HttpContext, but to inject the IHttpContextAccessor I need to add IHttpContextAccessor as a singleton in the application Startup:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
I researched it and this is the only way I found. I google it and IHttpContextAccessor was removed as a default in the dependency resolver because it is very heavy dependency. Is there any other way to achieve this?
Edit:
I wonder if instead of adding it as a Singleton to the dependency resolver, I could get in that same place the instance of the HttpContextAccessor to save it in my own singleton class?
If you are porting a legacy application to ASP.Net Core that is reasonably complex, it would require totally reengineering to work properly with the .Net Core DI system. If you don't want to do this, you can 'cheat' by making this functionality global again in a Service Locator. To do this (which is not recommended if you can avoid it):
public class RequestContextManager
{
public static RequestContextManager Instance { get; set; }
static RequestContextManager()
{
Instance = new RequestContextManager(null);
}
private readonly IHttpContextAccessor contextAccessor;
public RequestContextManager(IHttpContextAccessor contextAccessor)
{
this.contextAccessor = contextAccessor;
}
public HttpContext CurrentContext
{
get
{
if (contextAccessor == null)
return null;
return contextAccessor.HttpContext;
}
}
}
// In Startup.cs
public void Configure(IApplicationBuilder app,...)
{
...
RequestContextManager.Instance = new RequestContextManager(app.ApplicationServices.GetService<IHttpContextAccessor>());
...
}
// In your code
var httpContext = RequestContextManager.Instance.CurrentContext;
For HttpContext to be valid, the program flow calling your class must originate in a controller or some middleware component. You could just pass a reference to HttpContext to your class.
To directly answer the question of why, this GitHub Announcement states that it's non-trivial to keep the HttpContext state tracked in IHttpContextAccessor. So it was moved to as-needed only. The HttpContext is still available in a Controller, however, without this being injected.
I don't believe you're pulling in a new dependency on the project level, just into classes via dependency injection, or grabbing it from IServiceProvider when you need it.