This commit is contained in:
Steven Hildreth 2018-11-11 08:46:09 -06:00
parent a4c41e983d
commit 3590f87e43
11 changed files with 185 additions and 47 deletions

View file

@ -19,7 +19,7 @@ namespace Roadie.Api.Controllers
[Produces("application/json")]
[Route("image")]
[ApiController]
[Authorize]
// [Authorize]
public class ImageController : EntityControllerBase
{
private IImageService ImageService { get; }
@ -37,29 +37,6 @@ namespace Roadie.Api.Controllers
// return Ok(this._RoadieDbContext.Tracks.ProjectToType<models.Image>());
//}
//[HttpGet("{id}")]
//[ProducesResponseType(200)]
//[ProducesResponseType(404)]
//public IActionResult Get(Guid id)
//{
// var key = id.ToString();
// var result = this._cacheManager.Get<models.Image>(key, () =>
// {
// var d = this._RoadieDbContext.Images.FirstOrDefault(x => x.RoadieId == id);
// if (d != null)
// {
// return d.Adapt<models.Image>();
// }
// return null;
// }, key);
// if (result == null)
// {
// return NotFound();
// }
// return Ok(result);
//}
[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
@ -77,7 +54,7 @@ namespace Roadie.Api.Controllers
}
return File(fileContents:result.Data.Bytes,
contentType: result.ContentType,
fileDownloadName: result.Data.Caption ?? id.ToString(),
fileDownloadName: $"{ result.Data.Caption ?? id.ToString()}.jpg",
lastModified: result.LastModified,
entityTag: result.ETag);
}

View file

@ -6,6 +6,8 @@ using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Extensions;
using Roadie.Library.Imaging;
using Roadie.Library.Models;
using Roadie.Library.Utility;
using System;
@ -31,21 +33,25 @@ namespace Roadie.Api.Services
public async Task<FileOperationResult<Image>> ImageById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:image_by_id_operation:{0}", id);
var result = await this.CacheManager.GetAsync<FileOperationResult<Image>>(cacheKey, async () =>
var result = (await this.CacheManager.GetAsync($"urn:image_by_id_operation:{id}", async () =>
{
return await this.ImageByIdAction(id, etag);
}, data.Image.CacheRegionKey(id));
}, data.Image.CacheRegionKey(id))).Adapt<FileOperationResult<Image>>();
if (result.ETag == etag)
{
return new FileOperationResult<Image>(OperationMessages.NotModified);
}
if ((width.HasValue || height.HasValue) && result?.Data?.Bytes != null)
{
result.Data.Bytes = ImageHelper.ResizeImage(result?.Data?.Bytes, width.Value, height.Value);
result.ETag = EtagHelper.GenerateETag(this.HttpEncoder, result.Data.Bytes);
result.LastModified = DateTime.UtcNow;
this.Logger.LogInformation($"ImageById: Resized [{ id }], Width [{ width.Value }], Height [{ height.Value }]");
}
sw.Stop();
return new FileOperationResult<Image>(result.Messages)
{
Data = result?.Data,
Data = result.Data,
ETag = result.ETag,
LastModified = result.LastModified,
ContentType = result.ContentType,

View file

@ -61,8 +61,6 @@ namespace Roadie.Api
app.UseDeveloperExceptionPage();
}
loggerFactory.AddConsole(LogLevel.Trace);
app.UseCors("Cors");
app.UseAuthentication();
//app.UseSwagger();
@ -93,7 +91,7 @@ namespace Roadie.Api
services.AddSingleton<IHttpEncoder, HttpEncoder>();
var cacheManager = new MemoryCacheManager(this._loggerFactory.CreateLogger<MemoryCacheManager>(), new CachePolicy(TimeSpan.FromHours(4)));
var cacheManager = new DictionaryCacheManager(this._loggerFactory.CreateLogger<DictionaryCacheManager>(), new CachePolicy(TimeSpan.FromHours(4)));
services.AddSingleton<ICacheManager>(cacheManager);
services.AddDbContextPool<ApplicationUserDbContext>(

View file

@ -4,9 +4,8 @@
"IncludeScopes": false,
"Console": {
"LogLevel": {
"Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
"Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
"Microsoft.AspNetCore.Mvc.Razor": "Error",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
"Default": "Trace"
}
},

View file

@ -8,12 +8,12 @@ namespace Roadie.Library.Caching
public abstract class CacheManagerBase : ICacheManager
{
protected readonly CachePolicy _defaultPolicy = null;
protected readonly ILogger _logger = null;
protected ILogger Logger { get; }
protected readonly JsonSerializerSettings _serializerSettings = null;
public CacheManagerBase(ILogger logger, CachePolicy defaultPolicy)
{
this._logger = logger;
this.Logger = logger;
this._defaultPolicy = defaultPolicy;
this._serializerSettings = new JsonSerializerSettings
{
@ -64,7 +64,7 @@ namespace Roadie.Library.Caching
}
catch (Exception ex)
{
this._logger.LogError(ex, null, null);
this.Logger.LogError(ex, null, null);
}
return default(TOut);
}

View file

@ -0,0 +1,119 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace Roadie.Library.Caching
{
public class DictionaryCacheManager : CacheManagerBase
{
private Dictionary<string, object> Cache { get; }
public DictionaryCacheManager(ILogger logger, CachePolicy defaultPolicy)
: base(logger, defaultPolicy)
{
this.Cache = new Dictionary<string, object>();
}
public override bool Add<TCacheValue>(string key, TCacheValue value)
{
if(this.Cache.ContainsKey(key))
{
this.Cache.Remove(key);
}
this.Cache.Add(key, value);
return true;
}
public override bool Add<TCacheValue>(string key, TCacheValue value, string region)
{
return this.Add(key, value);
}
public override bool Add<TCacheValue>(string key, TCacheValue value, CachePolicy policy)
{
return this.Add(key, value);
}
public override bool Add<TCacheValue>(string key, TCacheValue value, string region, CachePolicy policy)
{
return this.Add(key, value);
}
public override void Clear()
{
this.Cache.Clear();
}
public override void ClearRegion(string region)
{
this.Clear();
}
public override bool Exists<TOut>(string key)
{
return this.Cache.ContainsKey(key);
}
public override bool Exists<TOut>(string key, string region)
{
return this.Exists<TOut>(key);
}
public override TOut Get<TOut>(string key)
{
if(!this.Cache.ContainsKey(key))
{
return default(TOut);
}
return (TOut)this.Cache[key];
}
public override TOut Get<TOut>(string key, string region)
{
return Get<TOut>(key);
}
public override TOut Get<TOut>(string key, Func<TOut> getItem, string region)
{
return Get<TOut>(key);
}
public override TOut Get<TOut>(string key, Func<TOut> getItem, string region, CachePolicy policy)
{
return Get<TOut>(key);
}
public override bool Remove(string key)
{
if(this.Cache.ContainsKey(key))
{
this.Cache.Remove(key);
}
return true;
}
public override bool Remove(string key, string region)
{
return this.Remove(key);
}
public async override Task<TOut> GetAsync<TOut>(string key, Func<Task<TOut>> getItem, string region)
{
var r = this.Get<TOut>(key, region);
if (r == null)
{
r = await getItem();
this.Add(key, r, region);
this.Logger.LogInformation($"-+> Cache Miss for Key [{ key }], Region [{ region }]");
}
else
{
this.Logger.LogInformation($"-!> Cache Hit for Key [{ key }], Region [{ region }]");
}
return r;
}
}
}

View file

@ -106,11 +106,11 @@ namespace Roadie.Library.Caching
{
r = await getItem();
this.Add(key, r, region);
Trace.WriteLine($"-+> Cache Miss for Key [{ key }], Region [{ region }]");
this.Logger.LogInformation($"-+> Cache Miss for Key [{ key }], Region [{ region }]");
}
else
{
Trace.WriteLine($"-!> Cache Hit for Key [{ key }], Region [{ region }]");
this.Logger.LogInformation($"-!> Cache Hit for Key [{ key }], Region [{ region }]");
}
return r;
}

View file

@ -62,7 +62,7 @@ namespace Roadie.Library.Caching
{
if (this._doTraceLogging)
{
this._logger.LogTrace("Added [{0}], Region [{1}]", key, region);
this.Logger.LogTrace("Added [{0}], Region [{1}]", key, region);
}
return this.Redis.StringSet(key, this.Serialize(value));
}
@ -74,7 +74,7 @@ namespace Roadie.Library.Caching
server.FlushAllDatabases();
if (this._doTraceLogging)
{
this._logger.LogTrace("Cleared Cache");
this.Logger.LogTrace("Cleared Cache");
}
}
@ -156,12 +156,12 @@ namespace Roadie.Library.Caching
{
if (this._doTraceLogging)
{
this._logger.LogTrace("Get Cache Miss Key [{0}], Region [{1}]", key, region);
this.Logger.LogTrace("Get Cache Miss Key [{0}], Region [{1}]", key, region);
}
}
else if (this._doTraceLogging)
{
this._logger.LogTrace("Get Cache Hit Key [{0}], Region [{1}]", key, region);
this.Logger.LogTrace("Get Cache Hit Key [{0}], Region [{1}]", key, region);
}
return result;
}

View file

@ -1,5 +1,9 @@
using System.Linq;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Roadie.Library.Extensions
{
@ -19,5 +23,35 @@ namespace Roadie.Library.Extensions
return OriginalEntity;
}
/// <summary>
/// Perform a deep Copy of the object using a BinaryFormatter.
/// IMPORTANT: the object class must be marked as [Serializable] and have an parameterless constructor.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T Clone<T>(this T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
using (Stream stream = new MemoryStream())
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
}

View file

@ -14,6 +14,10 @@ namespace Roadie.Library
public DateTimeOffset? LastModified { get; set; }
public string ContentType { get; set; }
public FileOperationResult()
{
}
public FileOperationResult(string message)
{
this.AddMessage(message);

View file

@ -4,6 +4,7 @@ using System.Linq;
namespace Roadie.Library
{
[Serializable]
public class OperationResult<T>
{
private List<Exception> _errors;