On an Net.Core 6 project I have the IEndpoint extension
public interface IEndpoint {
void Map(IEndpointRouteBuilder builder);
}
And an implementation example:
public class CountryEndpoint : IEndpoint {
public void Map(IEndpointRouteBuilder builder) {
builder.MapGet("countries", async ([FromServices] IService service) => {
List<Country> countries = await service.GetCountries();
return Results.Ok(countries);
})
.WithName("Countries");
.WithApiVersionSet(versionSet)
.MapToApiVersion( 1.0 );
}
}
I configure the endpoints on my application using:
builder.Services.AddEndpoints(typeof(Program));
WebApplication application = builder.Build();
application.MapEndpoints();
Where AddEndpoints and MapEndpoints extensions are:
public static IServiceCollection AddEndpoints(this IServiceCollection services, params Type[] types) {
services
.Scan(x => x.FromAssembliesOf(types).AddClasses(y => y.AssignableTo(typeof(IEndpoint))).AsImplementedInterfaces().WithScopedLifetime());
return services;
}
public static class ApplicationBuilderExtensions {
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder builder) {
using (IServiceScope scope = builder.ServiceProvider.CreateScope()) {
IEnumerable<IEndpoint> endpoints = scope.ServiceProvider.GetServices<IEndpoint>();
foreach (IEndpoint endpoint in endpoints)
endpoint.Map(builder);
}
return builder;
}
}
Question
On CountryEndpoint's Map` method I have:
.WithApiVersionSet(versionSet)
The versionSet variable is created in Program code as follows:
ApiVersionSet versionSet = application.NewApiVersionSet().HasApiVersion(new ApiVersion(1.0)).ReportApiVersions().Build();
How can I create such a variable and use it in Endpoints' Map method?
Usually the versionSet variable and the Map methods are in Program code.
You can create static class with corresponding static field (for example a partial Program class) and use it to store the value and use it in Map:
Top-level statement (Program.cs):
...
ApiVersionSet versionSet = application.NewApiVersionSet().HasApiVersion(new ApiVersion(1.0)).ReportApiVersions().Build();
VersionSet = versionSet;
application.MapEndpoints(); // use Program.VersionSet in IEndpoint.Map implementation
...
// end of top-level statement
static partial class Program
{
internal static ApiVersionSet VersionSet {get;set;}
}
But I would argue that making ApiVersionSet a parameter of IEndpoint.Map and ApplicationBuilderExtensions.MapEndpoints would be a much better approach:
public interface IEndpoint {
void Map(IEndpointRouteBuilder builder, ApiVersionSet versionSet);
}
public static class ApplicationBuilderExtensions {
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder builder, ApiVersionSet versionSet) {
using (IServiceScope scope = builder.ServiceProvider.CreateScope()) {
IEnumerable<IEndpoint> endpoints = scope.ServiceProvider.GetServices<IEndpoint>();
foreach (IEndpoint endpoint in endpoints)
endpoint.Map(builder, versionSet); // pass it here
}
return builder;
}
}
And in top-level statement:
ApiVersionSet versionSet = ...;
application.MapEndpoints(versionSet);
Related
I'm trying to make an unit test for a logger in an application.
For example I need to test the method Logger.info("some message"), but this method is static and return void.
Searching on Google I understand that I have to use Moq but am unable to implement that on the UnitTest class.
The Logger constructor does not have an argument and in x.Debug I have an error that says that I can't access
from instance reference.
Is there a way to implement UnitTest without editing the production code?
[TestClass()]
public class LoggerTests
{
[TestMethod()]
public void DebugTest()
{
var mock = new Mock<Logger>();
mock.Setup(x => x.Debug(It.IsAny<string>());
new Logger(mock.Object).AddLog("testing");
mock.VerifyAll;
}
}
Program.cs
private static void ConfigureLogger()
{
Logger.AddLog(new NLogAppender());
Logger.Level = TraceLevel.Verbose;
Logger.Info("Configured Logger");
}
Logger.cs
public class Logger
{
public static readonly List<IAppender> loggings = new List<IAppender>();
public static void AddLog(IAppender appender)
{
loggings.Add(appender);
}
public static TraceLevel Level { get; set; }
static Logger()
{
Level = TraceLevel.Verbose;
}
public static void Info(string message)
{
LogMessage(message);
}
}
NlogAppender.cs
public class NLogAppender : IAppender
{
public NLog.Logger logger;
public NLogAppender()
{
logger = LogManager.GetLogger(nameof(NLogAppender));
}
public void AddLog(string str)
{
}
}
IAppender.cs
public interface IAppender
{
void AddLog(string str);
}
You can't mock a static class, and you shouldn't mock the class/system under test.
Add a mock appender to the logger:
// Arrange
var logString = "test-info"
var appenderMock = new Mock<IAppender>();
appenderMock.Setup(a => a.AddLog(logString));
Logger.AddLog(appenderMock.Object);
// Act
Logger.Info(logString);
// Assert
// TODO: exactly once
appenderMock.VerifyAll();
Note this static class may persist data between tests causing unexpected results, consult your test framework for configuring this.
Apart from that, you usually don't want to roll your own logging infrastructure, there's lots of things you can do wrong and why reinvent the wheel? Plenty of ILogger(<T>) implementations around.
I'm using Web Api with the OWIN pipeline.
Startup.cs
public class Startup {
public void Configuration(IAppBuilder app) {
var container = new WindsorContainer().Install(FromAssembly.This());
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
// extension method to resolve controllers with Windsor.
app.UseWindsorApi(config, container);
}
}
MyClassInstaller.cs (IWindsorInstaller)
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IMyClass>().ImplementedBy<MyClass>()
.LifeStyle.PerWebRequest()
.DependsOn(new {
configSetting = ConfigurationManager.AppSettings["key"],
otherSetting = ???
}));
}
MyClass.cs & IMyClass.cs
public class MyClass : IMyClass {
private readonly string configSetting;
private readonly string otherSetting;
public MyClass(string configSetting, string otherSetting) {
this.configSetting = configSetting;
this.otherSetting = otherSetting;
}
public void DoSomething() {
// method that uses the settings that were set in the constructor.
}
}
public interface IMyClass {
void DoSomething();
}
MyController.cs
public class MyController : ApiController {
private readonly IMyClass myClass;
public MyController(IMyClass myClass) {
this.myClass = myClass;
}
[HttpGet]
[Route("")]
public async Task<IHttpActionResult> GetAsync() {
// uses this.myClass
}
}
Here's where I'm stuck. Whenever an instance of MyClass is resolved the value of otherSetting needs to be assigned.
The value of otherSetting is determined by two things.
1) The client_id claims value from the request.
2) An async call to a method that takes the client_id as a parameter and returns a string value. Which is what gets set into otherSetting
public async Task<string> GetOtherSetting(string client_id) {
return "value";
}
I'm not sure where to even begin to get Castle to inject a value based on those two criteria...
UPDATE:
I've updated to potatopeelings answer with some minor changes and it seems to be working fine.
.DynamicParameters(async (k, p) =>
{
var fundNameProvider = k.Resolve<IFundNameValueProvider>();
p["otherSetting"] = await fundNameProvider.GetFundNameAsync();
k.ReleaseComponent(fundNameProvider);
}))
I changed it to an async lambda so I can await the method.
I also called ReleaseComponent as I was under the impression that objects you manually Resolved with Castle you also needed to manually release.
Use UsingFactoryMethod and DynamicParamters
First, inject the current claims
...
Component.For<ClaimsIdentity>().UsingFactoryMethod(() => HttpContext.Current.User.Identity as ClaimsIdentity).LifestylePerWebRequest()
...
into a service (IOtherValueProvider - PerWebRequest) that has a GetOtherSetting method to wait on an async call (i.e. convert the async call to a synchronous call) to get otherSetting from the client_id extracted from the injected ClaimsIdentity
Then use DynamicParameters to get the value
... register your class ...
.DynamicParameters((kernel, parameters) =>
{
parameters["otherSetting"] = kernel.Resolve<IOtherValueProvider>().GetOtherSetting();
}))
I have the next problem, i dont understand why this code dont work i think is because i dont injectate the class of constructor by autofac but i dont know how do that, can us help me to do that the better way?
Before I add the generator this work if i comment the generator code in service work.
This is my code:
I have a class Controller that invoke a serv:
public class ZonesController : Controller
{
private IZoneService zoneService;
public ZonesController(IZoneService zoneService)
{
this.zoneService = zoneService;
}
[HttpGet]
//Do work
}
This is the service and interface:
public class ZoneService : IZoneService
{
private readonly IZoneRepository zoneRepository;
private readonly IDtoFactory dtoFactory;
private readonly ZoneGenerator zoneGenerator;
public ZoneService(IZoneRepository zoneRepository,
IDtoFactory dtoFactory,
ZoneGenerator zoneGenerator)
{
this.zoneRepository = zoneRepository;
this.dtoFactory = dtoFactory;
this.zoneGenerator = zoneGenerator;
}
public void Add(ZoneDetailDTO zone)
{
zoneGenerator.Generate(zone);
}
//Do Work
}
public interface IZoneService
{
void Add(ZoneDetailDTO zone);
//Do Methods
}
The generator invoke ohter class, factories:
public class ZoneGenerator
{
private readonly ZoneFactory zoneFactory;
private readonly IZoneRepository zoneRepository;
public ZoneGenerator(ZoneFactory zoneFactory, IZoneRepository zoneRepository)
{
this.zoneFactory = zoneFactory;
this.zoneRepository = zoneRepository;
}
public void Generate(ZoneDetailDTO zoneModel)
{
var zone = zoneFactory.Create(zoneModel);
zoneRepository.Add(zone);
}
}
The Factory:
public class ZoneFactory
{
private readonly ZoneMapFactory zoneMapFactory;
private readonly ZoneScheduleFactory zoneScheduleFactory;
public ZoneFactory(ZoneMapFactory zoneMapFactory,
ZoneScheduleFactory zoneScheduleFactory)
{
this.zoneMapFactory = zoneMapFactory;
this.zoneScheduleFactory = zoneScheduleFactory;
}
public Zone Create(zoneDetailDTO zone)
{
var map = zoneMapFactory.Create(zone.Map.Address, zone.Map.Latitude, zone.Map.Longitude);
var schedule = zoneScheduleFactory.Create(zone.Schedule.StartHour, zone.Schedule.EndHour);
return new Zone(zone.Name,
zone.ProvinceId,
map,
schedule,
zone.Tags);
}
}
And finally my container:
//method in Startup class Asp.Net Core
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_ => Configuration);
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
public class DefaultModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ZoneService>().As<IZoneService>();
builder.RegisterType<ZoneRepository>().As<IZoneRepository>();
builder.RegisterType<ProvinceService>().As<IProvinceService>();
builder.RegisterType<ProvinceRepository>().As<IProvinceRepository>();
builder.RegisterType<DtoFactory>().As<IDtoFactory>();
}
}
You have missed to add to your Load method the following:
builder.RegisterType<ZoneGenerator>().AsSelf();
builder.RegisterType<ZoneFactory>().AsSelf();
builder.RegisterType<ZoneMapFactory>().AsSelf();
builder.RegisterType<ZoneScheduleFactory>().AsSelf();
I am using Simple Injector for test purpose but pretty new on OOP. I am trying to create loosely couple classes. Here is the my scenario.
I have User repo and interface like this.
public class UserRepository : IUserRepository
{
public void Add(Model.User user)
{
Console.WriteLine("Name:"+user.Name+"\n"+"SurName:"+user.SurName);
}
public void Delete(int id)
{
throw new NotImplementedException();
}
}
public interface IUserRepository
{
void Add(User user);
void Delete(int id);
}
My TestInjectedClass Class and interface are something like this which I am planning to use in Program Main.
public class TestInjectedClass : ITestInjectedClass
{
private readonly IUserRepository _userRepository;
public TestInjectedClass(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void UserRepoRun()
{
var user = new User() {Id = 1,Name = "ada",SurName = "stack"};
_userRepository.Add(user);
}
}
public interface ITestInjectedClass
{
void UserRepoRun();
}
And My console program looks like this:
class Program
{
static ITestInjectedClass _testInjectedClass;
private static IUserRepository _userRepository;
static void Main(string[] args)
{
_testInjectedClass= new TestInjectedClass(_userRepository);
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
public Program()
{
Bootstrap.Start();
}
}
BootStrap class here:
class Bootstrap
{
public static void Start()
{
var container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
My problem when I run program, I am getting a value exception on the _userRepository inside TestInjectionClass.
How can I properly inject TestInjectionClass and UserRepository to Main Program. Thanks
You need to make Bootstrap.container available in Program.Main and then use it to create instances of classes instead of directly calling their constructors directly:
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
Of course you will need to expose it in Bootstrap for that to work:
class Bootstrap
{
public static Container container;
public static void Start()
{
container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
And call Bootstrap.Start from Program.Main:
static void Main(string[] args)
{
Bootstrap.Start();
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
The problem is because you are calling your Bootstrap code in Program class instance constructor.
So, actually when you start your program the execution environment, is calling entry point method Main. And your instance constructor is never executed.
Try changing your entry point method Main and 'Bootstrap' class code:
static void Main(string[] args)
{
var container = new Container();
Bootstrap.Start(container);
_testInjectedClass = container.GetInstance<TestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
class Bootstrap
{
public static void Start(Container container)
{
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
Please use SimpleInjector
Sample please refer
http://www.c-sharpcorner.com/UploadFile/4d9083/dependency-injection-using-simple-injector/
I have a OWIN/Katana self-hosted service app.
One of its functions is to service some data over WebAPI.
In this app I have a class called dataManager, which is responsible for retrieving the data, and passing it onto the API controller, which asked for it.
The data is ultimately served to a mobile platform, so it is very important to cache as much as possible for performance.
Is there a way to pre-load my DataManager at the application startup, and have it pre-execute it's linq queries?
The Application class looks like this:
namespace TaskManager
{
using System;
using Microsoft.Owin.Hosting;
public class TaskManagerApplication
{
protected IDisposable WebApplication;
public void Start()
{
WebApplication = WebApp.Start<WebPipeline>("http://*:8080");
}
public void Stop()
{
WebApplication.Dispose();
}
}
}
The Program class looks like this:
namespace TaskManager
{
using Topshelf;
internal class Program
{
private static int Main()
{
var exitCode = HostFactory.Run(host =>
{
host.Service<TaskManagerApplication>(service =>
{
service.ConstructUsing(() => new TaskManagerApplication());
service.WhenStarted(a => a.Start());
service.WhenStopped(a => a.Stop());
});
host.SetDescription("Task Manager");
host.SetDisplayName("Task Manager");
host.SetServiceName("TaskManager");
host.RunAsNetworkService();
});
return (int) exitCode;
}
}
}
And the data retrieval statement contained within DataManager class look like this:
var rawData = from data in new XPQuery<AccountView3.PipelineData>(uow)
where data.Stage.ToLower().Contains("won")
&& data.RevenueStartDate.Value.Year == DateTime.Today.Year
&& data.WeekOfTheYear >= priorWeekCutoff
select data;
What I do is create a public static class in the API library. That's where I modify the HttpConfiguration object. That is also where I define OnStartup() and OnShutdown() methods. I then call these methods in the pipeline class's methods (your WebPipeline class).
For example (in the MyWebApi library, where my controllers and stuff live):
public class Service
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.EnsureInitialized();
}
public static void OnStartup()
{
// add any startup logic here, like caching your data
}
public static void OnShutdown()
{
// add any cleanup logic here
}
}
Then in the pipeline class:
public class WebPipeline
{
public static void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
MyWebApi.Service.Register(config);
MyWebApi.Service.OnStartup();
app.UseWebApi(config);
}
public static void Shutdown()
{
MyWebApi.Service.OnShutdown();
}
}
Now your TaskManagerApplication.Start() will result in the API OnStartup() being called. Then you just have to add a call to WebPipeline.Shutdown() in your TaskManagerApplication.Stop() method.