How Can I Simplify Classes That Do Similar Things - c#

I am working on a project where I call an external API. I want to cache the API responses for a certain amount of time and have created a 5 classes that all do practically the same thing: get data from cache or if the cache doesn't have data, get data from the API.
I'm looking for suggestions on how to simply this code.
Class:
using DataCreator.Foo.Api;
using DataCreator.Foo.Models;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
namespace DataCreator.Foo.DataProvider
{
public class PerformanceStatusDataProvider
{
private readonly IMemoryCache memoryCache;
public PerformanceStatusDataProvider(IServiceProvider serviceProvider)
{
memoryCache = serviceProvider.GetService<IMemoryCache>();
}
public List<PerformanceStatus> GetPerformanceStatuses()
{
return memoryCache.GetOrCreate("performance_status", cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
return FooApi.Instance.GetPerformanceStatuses();
});
}
}
}

If all your DataProviders follow a similar syntax, it should be quite easy with generics:
public List<T> GetData<T>(string cacheKey, Func<List<T>> retrieveDataFromApi)
{
return memoryCache.GetOrCreate(cacheKey, cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
return retrieveDataFromApi();
});
}
You'd call this using something like:
GenericDataProvider.GetData("performance_status", FooApi.Instance.GetPerformanceStatuses);
Small details: you're calling an API and you're not using async/await (you most definitively should) and FooApi.Instance is a code smell, you're 50% using Dependency Injection and 50% hard-coding dependencies.

Related

Unit Testing Umbraco 8 Composers

I'm fairly new to unit testing so go easy on me! I'm attempting to use a fairly simple Umbraco 8 project as a bit of a test bed. I'm currently stuck on trying to test a composer which registers a dependency and having a tough time figuring out how to test it.
The code will probably speak volumes so without further ado, here's the composer I'd like to test. As you can see, it simply registers a service coded against an interface:
using Papermoon.Umbraco.Utils.Services;
using Papermoon.Umbraco.Utils.Services.Interfaces;
using Umbraco.Core;
using Umbraco.Core.Composing;
namespace Papermoon.Umbraco.Aldus.Core.Composers
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class ServicesComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Register<IPapermoonContentTypeContainerService, PapermoonContentTypeContainerService>();
}
}
}
After a lot of playing around, I found some code in the Umbraco source which means I can get a test passing based on the idea of registering a type. However, that is in no way in context of the ServicesComposer class. Hence, that wouldn't count against my code coverage and actually testing the class, rather than the ability to register something. Here's the code anyway:
using System;
using Moq;
using NUnit.Framework;
using Papermoon.Umbraco.Aldus.Core.Composers;
using Papermoon.Umbraco.Utils.Services;
using Papermoon.Umbraco.Utils.Services.Interfaces;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Composing.CompositionExtensions;
using Umbraco.Core.Logging;
namespace Papermoon.Umbraco.Aldus.Core.Tests.Composers
{
[TestFixture]
public class ServicesComposerTests
{
private ServicesComposer _servicesComposer;
[SetUp]
public void SetUp()
{
_servicesComposer = new ServicesComposer();
}
[Test]
public void Compose_WhenCalled_RegistersContentTypeContainerService()
{
Func<IFactory, IFactory> factoryFactory = null;
var mockedRegister = Mock.Of<IRegister>();
var mockedFactory = Mock.Of<IFactory>();
// the mocked register creates the mocked factory
Mock.Get(mockedRegister)
.Setup(x => x.CreateFactory())
.Returns(mockedFactory);
// the mocked register can register a factory factory
Mock.Get(mockedRegister)
.Setup(x => x.Register(It.IsAny<Func<IFactory, IFactory>>(), Lifetime.Singleton))
.Callback<Func<IFactory, IFactory>, Lifetime>((ff, lt) => factoryFactory = ff);
// the mocked factory can invoke the factory factory
Mock.Get(mockedFactory)
.Setup(x => x.GetInstance(typeof(IPapermoonContentTypeContainerService)))
.Returns(() => new Mock<IPapermoonContentTypeContainerService>().Object);
var logger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
var typeLoader = new TypeLoader(Mock.Of<IAppPolicyCache>(), "", logger);
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of<IRuntimeState>());
var factory = composition.CreateFactory();
var resolved = factory.GetInstance<IPapermoonContentTypeContainerService>();
Assert.IsNotNull(resolved);
}
}
}
And the below code shows where I am at the moment, and is probably close to what the test should look like (if a little messy currently). I'm potentially way off the mark here so any help would go down a storm!
using System;
using Moq;
using NUnit.Framework;
using Papermoon.Umbraco.Aldus.Core.Composers;
using Papermoon.Umbraco.Utils.Services;
using Papermoon.Umbraco.Utils.Services.Interfaces;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Composing.CompositionExtensions;
using Umbraco.Core.Logging;
namespace Papermoon.Umbraco.Aldus.Core.Tests.Composers
{
[TestFixture]
public class ServicesComposerTests
{
private ServicesComposer _servicesComposer;
[SetUp]
public void SetUp()
{
_servicesComposer = new ServicesComposer();
Current.Factory = new Mock<IFactory>().Object;
}
[Test]
public void Compose_WhenCalled_RegistersContentTypeContainerService()
{
var mockedRegister = Mock.Of<IRegister>();
var logger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
var typeLoader = new TypeLoader(Mock.Of<IAppPolicyCache>(), "", logger);
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of<IRuntimeState>());
_servicesComposer.Compose(composition);
var resolved = Current.Factory.GetInstance<IPapermoonContentTypeContainerService>();
Assert.IsNotNull(resolved);
}
}
}
I've also tried mocking up Composition to see if I could verify that the Register method has run but as this is a static method I get the following error:
Extension methods (here: RegisterExtensions.Register) may not be used in setup / verification expressions.
Here's the code that gets me to that error:
[Test]
public void Compose_WhenCalled_RegistersContentTypeContainerService()
{
Func<IFactory, IFactory> factoryFactory = null;
var mockedRegister = Mock.Of<IRegister>();
var mockedFactory = Mock.Of<IFactory>();
// the mocked register creates the mocked factory
Mock.Get(mockedRegister)
.Setup(x => x.CreateFactory())
.Returns(mockedFactory);
Mock.Get(mockedRegister)
.Setup(x => x.Register(It.IsAny<Func<IFactory, IFactory>>(), Lifetime.Singleton))
.Callback<Func<IFactory, IFactory>, Lifetime>((ff, lt) => factoryFactory = ff);
// the mocked factory can invoke the factory factory
Mock.Get(mockedFactory)
.Setup(x => x.GetInstance(typeof(IFactory)))
.Returns(() => factoryFactory?.Invoke(mockedFactory));
var logger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
var typeLoader = new TypeLoader(Mock.Of<IAppPolicyCache>(), "", logger);
var composition = new Mock<Composition>(mockedRegister, typeLoader, logger, new Mock<IRuntimeState>().Object);
composition.Verify(c => c.Register<IPapermoonContentTypeContainerService, PapermoonContentTypeContainerService>(It.IsAny<Lifetime>()));
}
Ultimately, I'm failing hard (and might have set my sights too high!), I'm not 100% sure on what to test here. My idea is that I want to test that the IPapermoonContentTypeContainerService is resolvable after _serviceComposer.Compose runs i.e. it's not null which ensures that it's been registered to the container. Potentially this isn't possible at which point, I wondered if testing that composition.Register<IPapermoonContentTypeContainerService, PapermoonContentTypeContainerService>(); was called was enough (as the actual registration part is third-party and therefore not to be tested). Or, am I barking up the wrong tree and this shouldn't actually be tested at all?
Thanks!
Ben
Register<TService, TImplementing> is a static extension method. You cannot mock extension methods, you'll need to look at the source for it & see what method it is calling under the hood.
For example, say I have a ILogger which exposes ILogger.Write(info level, string message) then I have an extension method:
public static void Info(this ILoggerlogger, string message) => logger.Write("Info", message);
When Info is called on a mocked instance of ILogger, the extension method is still called and the mocked ILogger.Write is called.
As you can see from the source code, the generic extension is calling another overload- that's the one you need to setup/verify:
composition.Verify(c => c.Register(typeof(IPapermoonContentTypeContainerService), typeof(PapermoonContentTypeContainerService), It.IsAny<Lifetime>()));
I'm not familiar with the service composers & suspect it's not possible; but rather than Compose(Composition composition), using IRegister (which Composition inherits from) would allow you to mock composition directly without having to mock it's dependencies...

Asp.net Core DI: Using SemaphoreSlim for write AND read operations with Singleton

I am re-tooling an ASP.NET CORE 2.2 app to avoid using the service locator pattern in conjunction with static classes. Double bad!
The re-tooling is involving the creation and injection of Singleton object as a repository for some global data. The idea here to avoid hits to my SQL server for some basic/global data that gets used over and over again in requests. However, this data needs to be updated on an hourly basis (not just at app startup). So, to manage the situation I am using SemaphoreSlim to handle one-at-a-time access to the data objects.
Here is a paired down sketch of what what I'm doing:
namespace MyApp.Global
{
public interface IMyGlobalDataService
{
Task<List<ImportantDataItem>> GetFilteredDataOfMyList(string prop1);
Task LoadMyImportantDataListAsync();
}
public class MyGlobalDataService: IMyGlobalDataService
{
private MyDbContext _myDbContext;
private readonly SemaphoreSlim myImportantDataLock = new SemaphoreSlim(1, 1);
private List<ImportantDataItem> myImportantDataList { get; set; }
public async Task<List<ImportantDataItem>> GetFilteredDataOfMyList(string prop1)
{
List<ImportantDataItem> list;
myImportantDataLock.WaitAsync();
try
{
list = myImportantDataList.Where(itm => itm.Prop1 == prop1).ToList();
}
finally
{
myImportantDataLock.Release();
}
return list;
}
public async Task LoadMyImportantDataListAsync()
{
// this method gets called when the Service is created and once every hour thereafter
myImportantDataLock.WaitAsync();
try
{
this.MyImportantDataList = await _myDbContext.ImportantDataItems.ToListAsync();
}
finally
{
myImportantDataLock.Release();
}
return;
}
public MyGlobalDataService(MyDbContext myDbContext) {
_myDbContext = myDbContext;
};
}
}
So in effect I am using the SemaphoreSlim to limit to one-thread-at-a-time access, for both READ and UPDATING to myImportantDataList. This is really uncertain territory for me. Does this seem like an appropriate approach to handle my injection of a global data Singleton throughout my app? Or should I expect insane thread locking/blocking?
The problem with using SemaphoreSlim is scalability.
As this is in a web application, it's fair to assume that you want to have the potential for more than one reader to access the data simultaneously. However, you are (understandably) limiting the number of requests for the semaphore that can be generated concurrently to 1 (to prevent concurrent read and write requests). This means you will serialize all reads too.
You need to use something like ReaderWriterLockSlim to allow multiple threads for reading, but ensure exclusive access for writing.
Creyke's answer hit the nail on the head for me: using ReaderWriterLockSlim. So I've marked it as the accepted answer. But I am posting my revised solution in case it might be helpful to anyone. Important to note that I'm using the following package to provide async functionality to ReaderWriterLockSlim: https://www.nuget.org/packages/Nito.AsyncEx/
using Nito.AsyncEx;
using System;
using System.Collections.Generic;
using System.Text;
namespace MyApp.Global
{
public interface IMyGlobalDataService
{
Task<List<ImportantDataItem>> GetFilteredDataOfMyList(string prop1);
Task LoadMyImportantDataListAsync();
}
public class MyGlobalDataService : IMyGlobalDataService
{
private MyDbContext _myDbContext;
private readonly AsyncReaderWriterLock myImportantDataLock = new AsyncReaderWriterLock();
private List<ImportantDataItem> myImportantDataList { get; set; }
public async Task<List<ImportantDataItem>> GetFilteredDataOfMyList(string prop1)
{
List<ImportantDataItem> list;
using (await myImportantDataLock.ReaderLockAsync())
{
list = myImportantDataList.Where(itm => itm.Prop1 == prop1).ToList();
}
return list;
}
public async Task LoadMyImportantDataListAsync()
{
// this method gets called when the Service is created and once every hour thereafter
using (await myImportantDataLock.WriterLockAsync())
{
this.MyImportantDataList = await _myDbContext.ImportantDataItems.ToListAsync();
}
return;
}
public MyGlobalDataService(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
};
}
}

how do i make a background worker to update a datastore every 5 minutes in asp.net core

I've followed the getting started tutorial and currently have a TODO CRUD app.
https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-web-api-mac?view=aspnetcore-2.1
I want to add a background worker that updates the todo database every 5 minutes and sets Item 1 to a random value for its Name, and isCompleted properties.
This is pretty easy in Java SpringBoot or Elixir's Phoenix...
Is there a quick and painless way in c# to do this?
The doc I found on Microsoft website was from 2012... so I assume there is a more elegant way to do this by now.
Edit: I went with DNTScheduler.Core and it was relatively painless to set up. Followed the exampleApp setup that was on github repo and here is the task i ended up using:
using System;
using System.Threading.Tasks;
using DNTScheduler.Core.Contracts;
using Microsoft.Extensions.Logging;
using myapp.Models;
namespace MyApp.Tasks
{
public class TaskOne : IScheduledTask
{
private readonly ILogger<DoBackupTask> _logger;
private readonly TodoContext _context; // autoinjects since it was added in startup.cs in configure()
public TaskOne(ILogger<DoBackupTask> logger, TodoContext context)
{
_logger = logger;
_context = context;
}
public Task RunAsync()
{
var todo = _context.TodoItems.Find(1);
if (todo == null)
{
return Task.CompletedTask;
}
string[] names = new string[] { "val1", "val2"};
Random r = new Random();
string random_name = names[r.Next(0, names.Length)];
todo.Name = random_name;
_context.TodoItems.Update(todo);
_context.SaveChanges();
_logger.LogInformation("Ran My Task\n\n ");
return Task.CompletedTask;
}
}
}
I would suggest you use Scheduler, there are some packages that can do that, but the best package that I have seen so far is DNTScheduler.Core
DNTScheduler.Core is a lightweight ASP.NET Core's background tasks runner and scheduler.
for more information, you can visit this link
I would argue that the correct answer is wrong if you want to follow the native practice.
Make use of IHostedService to perform repetitive actions.
Here’s an answer I’ve written that addresses that.
There is a saying i've read somewhere: "If its worth doing, its worth doing right. If its not worth doing right - find something that is."
So, as other colleagues already said, web application is not meant to be a container for background processes for reasons already mentioned.
Depending on your environment, you'll be much better off using:
windows services or even windows scheduler (on classic hosting) or some of the libraries for scheduling but outside of the web app. then, those scheduler, whichever it is, could just trigger API endpoint within your web app so you have business logic at one place
azure scheduler if you work with azure
pretty much anything else is looking for trouble when you don't need one.
In this sample I Insert a record to my database ( Word-Suggestion-Table in here) every hour using UnitOfWork and Repository Pattern. No error on Cannot consume scoped service *IUnitOfWork* from singleton
1- Add work class and IWork interface as below:
using System.Threading;
using System.Threading.Tasks;
namespace Map118.App.BackgroundTasks
{
public interface IWorker
{
Task DoWork(CancellationToken cancellationToken);
}
}
Work.cs :
using Map118.DataLayer.IRepositories;
using Map118.Models;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Map118.App.BackgroundTasks
{
public class Worker : IWorker
{
private readonly IServiceProvider serviceProvider;
public Worker( IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public async Task DoWork(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = serviceProvider.CreateScope())
{
var _unitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
while (!stoppingToken.IsCancellationRequested)
{
WordSuggestion wordSuggestion = new WordSuggestion()
{
word = Guid.NewGuid().ToString(),
};
await _unitOfWork.wordSuggestionRepository.Add(wordSuggestion);
await _unitOfWork.Save();
await Task.Delay(1000 * 3600);
}
}
}
}
}
}
2- Add another class as below:
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
namespace Map118.App.BackgroundTasks
{
public class UserActivitiesCleaner : BackgroundService
{
private readonly IWorker worker;
public UserActivitiesCleaner(IWorker worker)
{
this.worker = worker;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await worker.DoWork(stoppingToken);
}
}
}
3- Add services to Startup.cs :
services.AddHostedService<UserActivitiesCleaner>();
services.AddSingleton<IWorker, Worker>();

Use Same Class as Controller for Many Tables

I am new to asp.net and azure mobile services.
Have some questions:
1)I have used the TodoItemController to query data from azure table storage
(just used their sample class as given below)
How do i modify it so that it acts as Generic Class for all Tables and not just for one table.for eg:if i had another Table called person apart from Todo
i want it to use the same class for both tables
2)Is the method Im suggesting a bad design pattern and if so why?
3)I also dint understand how this class gets called.
Saw somewhere that ../tables/Todo
is mapped to this class.if thats the case.Where is the mapping done.?
4)Will ApiController achieve my purpose 1?if So an example please
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData;
using Microsoft.WindowsAzure.Mobile.Service;
using TempService.DataObjects;
using TempService.Models;
using System.Web.Http.OData.Query;
using System.Collections.Generic;
namespace TempService.Controllers
{
public class TodoItemController : TableController<TodoItem>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
// Create a new Azure Storage domain manager using the stored
// connection string and the name of the table exposed by the controller.
string connectionStringName = "StorageConnectionString";
var tableName = controllerContext.ControllerDescriptor.ControllerName.ToLowerInvariant();
DomainManager = new StorageDomainManager<TodoItem>(connectionStringName,
tableName, Request, Services);
}
public Task<IEnumerable<TodoItem>> GetAllTodoItems(ODataQueryOptions options)
{
// Call QueryAsync, passing the supplied query options.
return DomainManager.QueryAsync(options);
}
// GET tables/TodoItem/1777
public SingleResult<TodoItem> GetTodoItem(string id)
{
return Lookup(id);
}
// PATCH tables/TodoItem/1456
public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
{
return UpdateAsync(id, patch);
}
// POST tables/TodoItem
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE tables/TodoItem/1234
public Task DeleteTodoItem(string id)
{
return DeleteAsync(id);
}
}
}
So I will try to address your questions by point:
Yes and no. What you are trying to do is follow the Repository Pattern. So yes, you can make a BaseRepository that will do the bulk of the work with a generic data type. No, you will still have classes that inherit the base but specify the generic data type.
No this is not a bad design pattern.
So the TableController is a specialized ApiController for the data table. It is called via the route configuration that translates the URL "/tables/TodoItem/Id"
Again, the TableController is an ApiController. Not sure it will help, but there are a number of examples of the "Repository Pattern" for Azure Mobile Services. You can look here to get an idea:
http://www.codeproject.com/Articles/574357/Repository-Pattern-with-Windows-Azure-Mobile-Servi

How share data in WCF webservice

In order to call webservices dynamicly, I use WCF Dynamic Proxy from Microsoft
If I understood properly how it works, the code load the wsdl and compile on system class in order to consume distant webservice. I put this code in a "generic webservice". Its goal is to call any webservice with a request in parameter, and respond the answer of the webservice called.
But a problem appears : each request to this "generic webservice" pulls a new compilation of the proxy, and use time and ressources of the server.
My objective is to save instance of each proxies during a laps of time, and renew the instance when this laps is reached.
After few hours of googling, I found two ways :
Use my WCF webservice "by session", but I don't find any tutorial which explains how create easily the session layer
Use a singleton in order to save my datas and mutualize them with all instances of webservice
I exclude the first solution because I don't know how to do this. So I decided to use the second way.
There is my implementation :
FactoryTest is the singleton, contening the hashtable with instances
ProxyTest is the class which contains information about each instances of distant webservices
There is the code of FactoryTest :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WcfSamples.DynamicProxy;
using System.Threading;
using System.Collections;
namespace WS_Generic
{
public sealed class FactoryTest
{
private static object syncRoot = new Object();
private static Hashtable hashFactory = new Hashtable();
public static DynamicProxy getProxy(String sServiceWsdl, String sContract)
{
if (hashFactory[sServiceWsdl] == null || ((ProxyTest)hashFactory[sServiceWsdl]).getTimeFromCreation().TotalSeconds > 60 * 60 * 6)
{
lock (syncRoot)
{
if (hashFactory[sServiceWsdl] == null || ((ProxyTest)hashFactory[sServiceWsdl]).getTimeFromCreation().TotalSeconds > 60 * 60 * 6)
{
hashFactory.Add(sServiceWsdl, new ProxyTest(sServiceWsdl, sContract));
}
}
}
return ((ProxyTest)hashFactory[sServiceWsdl]).getProxy();
}
public static bool isProxyExists(String sServiceWsdl, String sContract)
{
lock (syncRoot)
{
return hashFactory[sServiceWsdl] == null ? false : true;
}
}
}
}
There is the code of ProxyTest :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using WcfSamples.DynamicProxy;
namespace WS_Generic
{
public class ProxyTest
{
private DateTime instanceCreation;
private String sServiceWsdl;
private String sContract;
private DynamicProxyFactory factory;
private volatile DynamicProxy proxy;
public ProxyTest(String sServiceWsdl, String sContract)
{
instanceCreation = DateTime.Now;
this.sServiceWsdl = sServiceWsdl;
this.sContract = sContract;
this.factory = new DynamicProxyFactory(this.sServiceWsdl);
this.proxy = factory.CreateProxy(this.sContract);
}
public DynamicProxy getProxy()
{
return proxy;
}
public TimeSpan getTimeFromCreation()
{
return DateTime.Now.Subtract(instanceCreation);
}
}
}
The problem is the webservice seems to reset the static status of FactoryTest after each call. So each time I called the webservice, my hashtable is empty and the factory create a new instance.
If anybody had already the problem of share datas between differents threads in WCF webservice (and found the solution), thanks in advance to give me some tips :)
PS : Sorry for my english, that's not my native language
If you store data in static variable WCF itself will not affect their purging. The problem must be somewhere else (application restart, app domain recreation, etc.).
Btw. this solution has only very limited usage because long living shared proxies should not be used and in many cases it can result in unexpected behavior. It can perhaps work only for services using basicHttpBinding.

Categories