CRUD operation works fine with the database but i am getting 500 internal server error for POST/PUT operation. I am getting 200 for GET/DELETE.
I worked with crud operation in ASP.NET and my code is running in prod. I have a requirement to migrate that to .NET Core. While testing i found that CRUD operations are working fine and i can see the changes related to data inside the SQL database but for Insert/Update, I am getting 500 error in response.
Code for .NET Framework (Working):-
public class ActivityUpdatesController : ApiController
{
private PortfolioMgmtEntities db = new PortfolioMgmtEntities();
// GET: api/ActivityUpdates
public IQueryable<ActivityUpdate> GetActivityUpdates()
{
return db.ActivityUpdates;
}
[Route("api/activityUpdates/getByProjectId")]
public IQueryable<ActivityUpdate> getActivityUpdatesByProjectId(int projectId)
{
IQueryable<ActivityUpdate> activityUpdates = from r in db.ActivityUpdates
where r.ProjectID == projectId
select r;
return activityUpdates;
}
// GET: api/ActivityUpdates/5
[ResponseType(typeof(ActivityUpdate))]
public IHttpActionResult GetActivityUpdate(int id)
{
ActivityUpdate activityUpdate = db.ActivityUpdates.Find(id);
if (activityUpdate == null)
{
return NotFound();
}
return Ok(activityUpdate);
}
// PUT: api/ActivityUpdates/5
[ResponseType(typeof(void))]
public IHttpActionResult PutActivityUpdate(int id, ActivityUpdate activityUpdate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != activityUpdate.RecordID)
{
return BadRequest();
}
db.Entry(activityUpdate).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ActivityUpdateExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/ActivityUpdates
[ResponseType(typeof(ActivityUpdate))]
[Route("api/activityUpdates/create")]
public IHttpActionResult PostActivityUpdate(int projectId, [FromBody] ActivityUpdate activityUpdate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
activityUpdate.ProjectID = projectId;
activityUpdate.UpdatedDate = DateTime.Now;
db.ActivityUpdates.Add(activityUpdate);
db.SaveChanges();
IQueryable<ActivityUpdate> activityUpdates = from au in db.ActivityUpdates
where au.ProjectID == projectId
select au;
return CreatedAtRoute("DefaultApi", new { controller = "ActivityUpdates" }, activityUpdates);
}
// DELETE: api/ActivityUpdates/5
[ResponseType(typeof(ActivityUpdate))]
public IHttpActionResult DeleteActivityUpdate(int id)
{
ActivityUpdate activityUpdate = db.ActivityUpdates.Find(id);
if (activityUpdate == null)
{
return NotFound();
}
db.ActivityUpdates.Remove(activityUpdate);
db.SaveChanges();
return Ok(activityUpdate);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool ActivityUpdateExists(int id)
{
return db.ActivityUpdates.Count(e => e.RecordID == id) > 0;
}
}
WebAPiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.EnableCors(new EnableCorsAttribute("*", "*", "GET,PUT,POST,DELETE"));
}
Code for .NET Core (Not Working):-
public class ActivityUpdatesController : Controller
{
private aeportfoliomgmtdbContext db = new aeportfoliomgmtdbContext();
// GET: api/ActivityUpdates
public IQueryable<ActivityUpdates> GetActivityUpdates()
{
return db.ActivityUpdates;
}
[HttpGet]
[Route("api/activityUpdates/getByProjectId")]
public IQueryable<ActivityUpdates> getActivityUpdatesByProjectId(int projectId)
{
IQueryable<ActivityUpdates> activityUpdates = from r in db.ActivityUpdates
where r.ProjectId == projectId
select r;
return activityUpdates;
}
[HttpPost]
[Route("api/activityUpdates/create")]
public IActionResult PostActivityUpdate(int projectId, [FromBody] ActivityUpdates activityUpdate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
activityUpdate.ProjectId = projectId;
activityUpdate.UpdatedDate = DateTime.Now;
db.ActivityUpdates.Add(activityUpdate);
db.SaveChanges();
IQueryable<ActivityUpdates> activityUpdates = from au in db.ActivityUpdates
where au.ProjectId == projectId
select au;
return CreatedAtRoute("DefaultApi", new { controller = "ActivityUpdates" }, activityUpdates);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool ActivityUpdateExists(int id)
{
return db.ActivityUpdates.Count(e => e.RecordId == id) > 0;
}
}
startup.cs
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)
{
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseCors("CorsPolicy");
app.UseMvc(routes =>
{
routes.MapRoute(
name: "DefaultApi",
template: "api/{controller}/{id}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
}
I am unable to find where is the mistake. Could you please help me to solve this issue? Any help will be appreciated.
If you want to return GetActivityUpdates like web api, try to define the route name above the GetActivityUpdates method.
[HttpGet("api/activityUpdates/GetActivityUpdates", Name = "GetActivityUpdates")]
public IQueryable<ActivityUpdates> GetActivityUpdates()
{
return db.ActivityUpdates;
}
[HttpGet]
[Route("api/activityUpdates/getByProjectId")]
public IQueryable<ActivityUpdates> getActivityUpdatesByProjectId(int projectId)
{
IQueryable<ActivityUpdates> activityUpdates = from r in db.ActivityUpdates
where r.ProjectId == projectId
select r;
return activityUpdates;
}
[HttpPost]
[Route("api/activityUpdates/create")]
public IActionResult PostActivityUpdate(int projectId, [FromBody] ActivityUpdates activityUpdate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
activityUpdate.ProjectId = projectId;
activityUpdate.UpdatedDate = DateTime.Now;
db.ActivityUpdates.Add(activityUpdate);
db.SaveChanges();
IQueryable<ActivityUpdates> activityUpdates = from au in db.ActivityUpdates
where au.ProjectId == projectId
select au;
return CreatedAtRoute("GetActivityUpdates", activityUpdates);
}
Please try to return Ok() from your post method not created route and check is it working or not. If it is work then may be you does not define the route that you use in created route.
Related
I'm working on a program that I take an excel file to a SQL database. I'm using EPPlus -Version 4.5.2.1. I keep getting errors when I import excel file Movie. SqlException: Cannot insert explicit value for identity column in table 'Movie' when IDENTITY_INSERT is set to OFF. DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
WebApplication14.Controllers.HomeController.Import(IFormFile file) in HomeController.cs
+
await _dbContext.SaveChangesAsync();
The HomeController Code:
namespace WebApplication14.Controllers
{
public class HomeController : Controller
{
private readonly ApplicationDbContext _dbContext;
public HomeController(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<List<Movie>> Import(IFormFile file)
{
var list = new List<Movie>();
using (var stream = new MemoryStream())
{
await file.CopyToAsync(stream);
using (var package = new ExcelPackage(stream))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
var rowcount = worksheet.Dimension.Rows;
var colcount = worksheet.Dimension.Columns;
for (int row = 2; row < rowcount; row++)
{
list.Add(new Movie
{
Id = int.Parse(worksheet.Cells[row, 1].Value.ToString().Trim()),
Title = worksheet.Cells[row, 2].Value.ToString().Trim(),
Genre = worksheet.Cells[row, 3].Value.ToString().Trim()
});
}
}
}
//SaveDataToDb(list);
_dbContext.Movie.AddRange(list);
await _dbContext.Database.ExecuteSqlCommandAsync(#"SET IDENTITY_INSERT [MovieList-1].[dbo].[Movie] ON");
await _dbContext.SaveChangesAsync();
await _dbContext.Database.ExecuteSqlCommandAsync(#"SET IDENTITY_INSERT [MovieList-1].[dbo].[Movie] OFF");
return list;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Model Movie
namespace WebApplication14.Models
{
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
public string Genre { get; set; }
}
}
DbContext Code
namespace WebApplication14.Models
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Movie> Movie { get; set; }
}
}
My Migration Code
public partial class MoviesToDb : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Movie",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(nullable: true),
Genre = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Movie", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Movie");
}
}
}
Startup Code
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)
{
services.AddControllersWithViews();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
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;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
My AppSettings.Json ConnectionString
"ConnectionStrings": {
"DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=MovieList-1;Trusted_Connection=True;MultipleActiveResultSets=true"
},
View/Home/Index
#{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about building Web apps with ASP.NET Core.</p>
<div class="container">
<form method="post" asp-controller="Home" asp-action="Import" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">Import From Excel</button>
</form>
</div>
</div>
EF will open and close the connection after each operation by default. This causes the SqlConnection to be returned to the Connection Pool, and its state is cleared, including dropping temp tables, and resetting session-level SET setting, each time it's fetched from the pool.
If you explicitly open the DbContext's connection (or start a transaction), the IDENTITY_INSERT setting should still be in effect when you call SaveChanges():
_dbContext.Database.OpenConnection();
_dbContext.Movie.AddRange(list);
await _dbContext.Database.ExecuteSqlCommandAsync(#"SET IDENTITY_INSERT [MovieList-1].[dbo].[Movie] ON");
await _dbContext.SaveChangesAsync();
await _dbContext.Database.ExecuteSqlCommandAsync(#"SET IDENTITY_INSERT [MovieList-1].[dbo].[Movie] OFF");
I have created an attribute for action names. I want to get the attribute names in my service. I tried so many solutions but it doesn't return anything.
This is my attribute class:
public class CustomeAttribute : ActionFilterAttribute
{
public string Name { get; set; }
}
This is the action that I used the attribute for:
[Custome(Name ="ُShow courses")]
public IActionResult Index()
{
var course = _courseService.GetAllCourses();
return View(course);
}
This is the method that I want to return the attribute name:
public IList<ActionAndControllerName> AreaAndActionAndControllerNamesList(Assembly asm)
{
var contradistinction = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type =>
type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Public))
.Select(x => new
{
Controller = x.DeclaringType?.Name,
//Action = x.Name,
//Action=x.DeclaringType?.GetCustomAttributes(typeof(CustomeAttribute), false),
//
Action=x.DeclaringType?.CustomAttributes.Where(c=>c.AttributeType==typeof(CustomeAttribute)),
// Action=x.DeclaringType?.GetCustomAttributes(typeof(CustomeAttribute), false),
// Action=x.DeclaringType?.CustomAttributes(typeof(CustomeAttribute), false),
//Action=x.DeclaringType?.GetCustomAttribute(typeof(CustomeAttribute), false),
Action=x.DeclaringType?.GetCustomAttributes<CustomeAttribute>(),
//Action = x.DeclaringType?.GetCustomAttributes().Where(a => a.GetType() ==
typeof(CustomeAttribute))
Area = x.DeclaringType?.CustomAttributes.Where(c => c.AttributeType ==
typeof(AreaAttribute)),
});
}
As I said I tried the solutions above that are commented but none of them worked. What should I do?
You can try to save Name to some place in ActionfilterAttribute.Here is a demo to save data to session in OnActionExecuting method:
TestController:
SomeOtherClass _someOtherClass;
public TestController(SomeOtherClass someOtherClass)
{
_someOtherClass = someOtherClass;
}
[Custome(Name = "Show courses")]
public IActionResult TestActionFilterAttribute()
{
var Name = _someOtherClass.TestGet();
return Ok();
}
SomeOtherClass:
public class SomeOtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
private ISession _session => _httpContextAccessor.HttpContext.Session;
public SomeOtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string TestGet()
{
return _session.GetString("Custome_Name");
}
}
Startup.cs(IHttpContextAccessor can help get seesion outside controller):
public void ConfigureServices(IServiceCollection services)
{
...
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromDays(1);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<SomeOtherClass, SomeOtherClass>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
...
}
CustomeAttribute:
public class CustomeAttribute: ActionFilterAttribute
{
public string Name { get; set; }
public override void OnActionExecuting(ActionExecutingContext
context)
{
if (Name != null)
{
context.HttpContext.Session.SetString("Custome_Name", Name);
}
}
public override void OnActionExecuted(ActionExecutedContext
context)
{
}
}
result:
I found the solution.I shouldn't have used "DeclaringType" in service.
This is the solution:
var contradistinction = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type =>
type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Public))
.Select(x => new
{
Controller = x.DeclaringType?.Name,
Action = x.GetCustomAttribute<CustomeAttribute>()?.Name,
Area = x.DeclaringType?.CustomAttributes.Where(c => c.AttributeType ==
typeof(AreaAttribute)),
});
Can you explain to me how to add sort, filtering and paging to my ASP.NET Web API, so I could write url like this
http://localhost:8000/api/Meetings?sort_by=name&sort_type=asc&s=Joh&page=1&page_size=3
I have this MeetingsController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using WebApplication3.Models;
namespace WebApplication3.Controllers
{
[Route("api/Meetings")]
[ApiController]
public class MeetingsController : ControllerBase
{
private readonly MeetingContext _context;
public MeetingsController(MeetingContext context)
{
_context = context;
}
//GET: api/Meetings
[HttpGet]
public async Task<ActionResult<IEnumerable<Meeting>>> GetMeetings()
{
return await _context.Meetings.ToListAsync();
}
// GET: api/Meetings/5
[HttpGet("{id}")]
public async Task<ActionResult<Meeting>> GetMeeting(string id)
{
var meeting = await _context.Meetings.FindAsync(id);
if (meeting == null)
{
return NotFound();
}
return meeting;
}
// PUT: api/Meetings/5
[HttpPut("{id}")]
public async Task<IActionResult> PutMeeting(string id, Meeting meeting)
{
if (id != meeting.Id)
{
return BadRequest();
}
_context.Entry(meeting).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MeetingExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Meetings
[HttpPost]
public async Task<ActionResult<Meeting>> PostMeeting(Meeting meeting)
{
if (ModelState.IsValid)
{
Guid obj = Guid.NewGuid();
meeting.Id = obj.ToString();
_context.Meetings.Add(meeting);
}
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (MeetingExists(meeting.Id))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtAction(nameof(GetMeeting), new { id = meeting.Id }, meeting);
}
// DELETE: api/Meetings/5
[HttpDelete("{id}")]
public async Task<ActionResult<Meeting>> DeleteMeeting(string id)
{
var meeting = await _context.Meetings.FindAsync(id);
if (meeting == null)
{
return NotFound();
}
_context.Meetings.Remove(meeting);
await _context.SaveChangesAsync();
return meeting;
}
private bool MeetingExists(string id)
{
return _context.Meetings.Any(e => e.Id == id);
}
}
}
try it:
this is only a sample:
//GET: api/Meetings
[HttpGet]
public async Task<ActionResult<IEnumerable<Meeting>>> GetMeetings(string sort_by, string sort_type, string s, int page , int page_size)
{
IQueryable<Meeting> query = _context.Meetings;
switch (sort_by)
{
case "name":
if (sort_type == "asc")
{
query = query.orderby(c => c.name);
}
else
{
query = query.OrderByDescending(c => c.name);
}
break;
case "surname":
if (sort_type == "asc")
{
query = query.orderby(c => c.surname);
}
else
{
query = query.OrderByDescending(c => c.surname);
}
break;
//do more
}
//your search
if (!string.IsNullOrEmpty(s))
{
query = query.where(c => c.name.Contains(s));
}
return await query.Skip((page - 1)* page_size).Take(page_size).ToListAsync();
}
We are facing problems with Redis caching and it's causing crashes in our site.
The following is how we implemented it:
We used the following connection string:
"*******.redis.cache.windows.net:6380,password=*****=,ssl=True,abortConnect=False"
We created a service class:
using Microsoft.Extensions.Options;
using SarahahDataAccessLayer;
using StackExchange.Redis;
using System;
namespace Sarahah.Services
{
public class RedisService
{
private static Lazy<ConnectionMultiplexer> lazyConnection;
private readonly ApplicationSettings _settings;
public RedisService(IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
return ConnectionMultiplexer.Connect(_settings.RedisConnection);
});
}
public ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
}
}
Then in Startup.cs I use the following:
services.AddSingleton<RedisService>();
Then in controllers we use dependency injection and we assign to a multiplexer:
connectionMultiplexer = redisService.Connection;
This is how we get from the cache:
private async Task<string> GetFromCache(string key)
{
if (connectionMultiplexer.IsConnected)
{
var cache = connectionMultiplexer.GetDatabase();
return await cache.StringGetAsync(key);
}
else
{
return null;
}
}
This is how we delete:
private async Task DeleteFromCache(string subdomain)
{
if (connectionMultiplexer.IsConnected)
{
var cache = connectionMultiplexer.GetDatabase();
await cache.KeyDeleteAsync(subdomain).ConfigureAwait(false);
}
}
This is how we add:
{
if (connectionMultiplexer.IsConnected)
{
var cache = connectionMultiplexer.GetDatabase();
TimeSpan expiresIn;
// Search Cache
if (key.Contains("-"))
{
expiresIn = new TimeSpan(0, GetMessagesCacheExpiryMinutes, 0);
}
// User info cache
else
{
expiresIn = new TimeSpan(GetProfileCacheExpiryHours, 0, 0);
}
await cache.StringSetAsync(key, serializedData, expiresIn).ConfigureAwait(false);
}
However, we get the following error:
No connection is available to service this operation
Although we have a lot of users, we only see few connections in Azure portal:
Please note that we hosted the redis cache in the same region of the web app.
Your support is appreciated.
Each time your dependency injection calls instantiates the RedisService class, your code ends up assigning a new Lazy<ConnectionMultiplexer> to lazyConnection, thus resulting in a new connection as well as a connection leak as you are not calling Close() or Dispose() on the old lazyConnection.
Try changing your code like this:
In Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
.........<whatever you have here>
services.AddSingleton<RedisService>();
services.Configure<ApplicationSettings>(options => Configuration.GetSection("ApplicationSettings").Bind(options));
}
RedisService.cs
public class RedisService
{
private readonly ApplicationSettings _settings;
private static Lazy<ConnectionMultiplexer> lazyConnection;
static object connectLock = new object();
public RedisService(IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
if (lazyConnection == null)
{
lock (connectLock)
{
if (lazyConnection == null)
{
lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
return ConnectionMultiplexer.Connect(_settings.RedisConnection);
});
}
}
}
}
public static ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
}
ApplicationSettings.cs
public class ApplicationSettings
{
public string RedisConnection { get; set; }
}
appsettings.json
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"ApplicationSettings": {
"RedisConnection": "yourcachename.redis.cache.windows.net:6380,password=yourpassword,ssl=True,abortConnect=False,syncTimeout=4000"
}
}
HomeController.cs
public class HomeController : Controller
{
private RedisService redisService;
private ConnectionMultiplexer connectionMultiplexer;
public HomeController(IOptions<ApplicationSettings> settings)
{
redisService = new RedisService(settings);
connectionMultiplexer = RedisService.Connection;
}
public IActionResult Index()
{
AddToCache("foo1", "bar").GetAwaiter().GetResult();
return View();
}
private async Task<string> GetFromCache(string key)
{
if (connectionMultiplexer.IsConnected)
{
var cache = connectionMultiplexer.GetDatabase();
return await cache.StringGetAsync(key);
}
else
{
return null;
}
}
private async Task DeleteFromCache(string subdomain)
{
if (connectionMultiplexer.IsConnected)
{
var cache = connectionMultiplexer.GetDatabase();
await cache.KeyDeleteAsync(subdomain).ConfigureAwait(false);
}
}
private async Task AddToCache(string key, string serializedData)
{
var GetMessagesCacheExpiryMinutes = 5;
var GetProfileCacheExpiryHours = 1;
if (connectionMultiplexer.IsConnected)
{
var cache = connectionMultiplexer.GetDatabase();
TimeSpan expiresIn;
// Search Cache
if (key.Contains("-"))
{
expiresIn = new TimeSpan(0, GetMessagesCacheExpiryMinutes, 0);
}
// User info cache
else
{
expiresIn = new TimeSpan(GetProfileCacheExpiryHours, 0, 0);
}
await cache.StringSetAsync(key, serializedData, expiresIn).ConfigureAwait(false);
}
}
When I access the swagger url: http//localhost:50505/swagger/index. I got the 500 error.
Please help me to figure out.
namespace BandwidthRestriction.Controllers
{
[Route("api/[controller]")]
public class BandwidthController : Controller
{
private SettingDbContext _context;
private readonly ISettingRespository _settingRespository;
public BandwidthController(ISettingRespository settingRespository)
{
_settingRespository = settingRespository;
}
public BandwidthController(SettingDbContext context)
{
_context = context;
}
// GET: api/Bandwidth
[HttpGet]
public IEnumerable<Setting> GetSettings()
{
return _settingRespository.GetAllSettings();
}
// GET: api/Bandwidth/GetTotalBandwidth/163
[HttpGet("{facilityId}", Name = "GetTotalBandwidth")]
public IActionResult GetTotalBandwidth([FromRoute] int facilityId)
{
// ...
return Ok(setting.TotalBandwidth);
}
// GET: api/Bandwidth/GetAvailableBandwidth/163
[HttpGet("{facilityId}", Name = "GetAvailableBandwidth")]
public IActionResult GetAvailableBandwidth([FromRoute] int facilityId)
{
// ...
var availableBandwidth = setting.TotalBandwidth - setting.BandwidthUsage;
return Ok(availableBandwidth);
}
// PUT: api/Bandwidth/UpdateBandwidthChangeHangup/163/10
[HttpPut]
public void UpdateBandwidthChangeHangup([FromRoute] int facilityId, [FromRoute]int bandwidth)
{
_settingRespository.UpdateBandwidthHangup(facilityId, bandwidth);
}
// PUT: api/Bandwidth/UpdateBandwidthChangeOffhook/163/10
[HttpPut]
public void UpdateBandwidthChangeOffhook([FromRoute] int facilityId, [FromRoute] int bandwidth)
{
_settingRespository.UpdateBandwidthOffhook(facilityId, bandwidth);
}
// POST: api/Bandwidth/PostSetting/163/20
[HttpPost]
public bool PostSetting([FromRoute] int facilityId, [FromRoute]int bandwidth)
{
//
return false;
}
}
The corresponding configuration code in Startup.cs is
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<SettingDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddMvc();
services.AddSwaggerGen();
services.ConfigureSwaggerDocument(options =>
{
options.SingleApiVersion(new Info
{
Version = "v1",
Title = "Bandwidth Restriction",
Description = "Api for Bandwidth Restriction",
TermsOfService = "None"
});
// options.OperationFilter(new Swashbuckle.SwaggerGen.XmlComments.ApplyXmlActionComments(pathToDoc));
});
services.ConfigureSwaggerSchema(options =>
{
options.DescribeAllEnumsAsStrings = true;
//options.ModelFilter(new Swashbuckle.SwaggerGen.XmlComments.ApplyXmlTypeComments(pathToDoc));
});
// Add application services.
services.AddTransient<ISettingRespository, SettingRespository>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{facilityId?}");
routes.MapRoute(
name: "",
template: "{controller}/{action}/{facilityId}/{bandwidth}");
});
app.UseSwaggerGen();
app.UseSwaggerUi();
}
In firefox: the error is unable to load swagger ui
Your route attributes are wrong. The routes for GetAvailableBandWidth and GetTotalBandWidth are both mapped to the route api/bandwidth/{facilityId} and not, as your comments suggests, to api/Bandwidth/GetAvailableBandwidth/{facilityId} and api/Bandwidth/GetTotalBandwidth/{facilityId}. The same goes, sort of, for your put methods.
When you register two identical routes, one will fail and throws an exception. Hence the http status code 500.
You can fix it like this:
// GET: api/Bandwidth/GetTotalBandwidth/163
[HttpGet("GetTotalBandwidth/{facilityId}", Name = "GetTotalBandwidth")]
public IActionResult GetTotalBandwidth(int facilityId)
{
// ...
return Ok(setting.TotalBandwidth);
}
// GET: api/Bandwidth/GetAvailableBandwidth/163
[HttpGet("GetAvailableBandwidth/{facilityId}", Name = "GetAvailableBandwidth")]
public IActionResult GetAvailableBandwidth(int facilityId)
{
// ...
var availableBandwidth = setting.TotalBandwidth - setting.BandwidthUsage;
return Ok(availableBandwidth);
}
// PUT: api/Bandwidth/UpdateBandwidthChangeHangup/163/10
[HttpPut("UpdateBandwidthChangeHangup/{facilityId}/{bandwidth}")]
public void UpdateBandwidthChangeHangup(int facilityId, int bandwidth)
{
_settingRespository.UpdateBandwidthHangup(facilityId, bandwidth);
}
// PUT: api/Bandwidth/UpdateBandwidthChangeOffhook/163/10
[HttpPut("UpdateBandwidthChangeOffhook/{facilityId}/{bandwidth}")]
public void UpdateBandwidthChangeOffhook(int facilityId, int bandwidth)
{
_settingRespository.UpdateBandwidthOffhook(facilityId, bandwidth);
}
Please note I removed the [FromRoute] attributes because they are not necessary.