basic c# architecture and class handling question - c#

Ok guys, this is very basic stuff I think.
I'm only getting familiar with C# and object oriented languages.
So here is a basic project I'm developping :
namespace MyProject
{
class MyProject
{
public Logger Logs = new Logger();
public WebServer Web = new WebServer();
static void Main()
{
// blabla
}
}
}
The logger is there to simply create a log file and when its "Add(string str)" method is called, it adds a line in the log file.
The webserver is my own webserver, opening a socket etc ...
I'd like my webserver to be able to use my Add method of the logger... how am I supposed to achieve that ?
Inside my webserver class, using something like "MyProject.Logs.Add(string str)" doesn't seem to work.
So how can I reference it ?
I don't want to create a new instance of my Logger class inside my webserver, because I want to write everyting in the same text file (I might have more module running than just a webserver as well).
So I'd like to use the instance I created in my Main method, inside my Webserver class...
I hope this makes sense ...

A couple of suggestions:
Logs and Web should be private. Those are implementation details of your class. They're nobody else's business.
Pass the instance of your logger to your web server:
public WebServer Web = new WebServer(Logs);
Your web server can now have its very own copy:
private Logger Logs {get;set;}
public WebServer(Logger logs)
{
Logs = logs;
}
public void DoSomething()
{
Logs.Add("I did something!");
}

MyProject.Logs.Add(string str) does not work because Logs member is not static, which means it can be different for different instances of your class (which are created by operator new). The compiler can't know which instance you are referring to if you don't specify it.
If you mark Logs as static, then it will work.
However, making it static makes your project less customizable (for example you will not be able to start two web-servers with two different log-files in the same program). That's why what John Saunders suggested is usually considered better.

You can do this easily by passing a reference to the Logger instance you created in within MyProject to your instance of WebServer.
In your WebServer class, you can make a property (a getter/setter) of type Logger, so that WebServer knows about the Logger you want to use. Another alternative (probably better) is to add a parameter to the constructor of WebServer that takes the Logger. Pseudo code for adding the property:
public class WebServer
{
public WebServer(Logger l)
{
Log = l;
}
//relevant code....
public Logger Log { get; set; } //Short hand property declaration, see http://msdn.microsoft.com/en-us/library/bb384054.aspx
}
From inside the WebServer class, you can use the logger like Logger.Add("some text...");
Then, in your Main method, you can pass in your instance of Logger like so:
namespace MyProject
{
class MyProject
{
public static Logger Logs = new Logger();
public static WebServer Web;
static void Main()
{
Web = new WebServer(Logs);
}
}
}

Related

ASP.NET Core 2.1 - Run attribute's code without reflection

I've defined the following attribute:
class MyAttribute: RouteAttribute, IActionModelConvention, IActionHttpMethodProvider
{
public IEnumerable<string> HttpMethods { get; }
public MyAttribute(string template) : base(UpdateTemplate(template))
{
HttpMethods = new[] { HttpMethod.Post.Method };
}
public void Apply(ActionModel action)
{
Foo();
}
}
The idea is to run Foo() without the need to use reflection and manually look for methods with the provided attribute.
Now, MVC will run Apply(action) only after the web application got its first request. I'm looking for a solution which will cause a method to run inside the attribute context without the need to find it by reflection and run a Foo().
Foo() does not have to be necessarily inside the attribute.
Any solution that allows me to have the instance of the attribute and on the startup of my application will be greeted.
Edit: For clarification, what I am trying to achieve is to use MVC's internal mechanism that searches for classes which implement certain interfaces and runs a certain function they implement. For an example here I used IActionModelConvention to run Foo() when using said mechanism. The problem here is that Foo() will run only after the routing mechanism is fired which only happens after a request was sent to the application. I'm looking for something to run my code as the application starts and to have my attribute's instance so I can pass Foo(this.someAttributeField) to it

How to call constructor of class which are instantiated through Structure Map in C#

I have an interface called ILogger which basically contains some methods for logging.
Ilogger.cs
public interface ILogger
{
void LogError(string message, Exception exception = null);
void LogMessage(string message);
void LogValidationError(UploadResult uploadResult);
void LogValidationError(ValidationResult validationResult);
void LogProcessingError(string processingError);
}
I have a LogHelper class which implements this interface. The LogHelper class is instantiated through StructureMap like
ObjectFactory.Initialize(
request =>
{
request.For<ILogger>().Singleton().Use<LogHelper>();
});
I have many classes in whose constructor I just instantiate this class and call methods to log the information.
For eg: I have a class say Dummy1 in whose constructor I instantiate the LogHelper as:
public Dummy1()
{
this.logger = ObjectFactory.GetInstance<ILogger>();
}
In LogHelper I have method which basically creates log file and writes the message passed as parameter to it.
public void LogMessage(string message)
{
using (var writer = this.GetTextWriter(this.messageFilename))
{
writer.WriteLine(message);
}
}
Currently the filename is hardcoded into a constant property of LogHelper class as private string messageFilename = "logs\\UserCreationResult.log";
But I want the Filename to be dynamically sent whenever the LogHelper is instantiated.
I thought of having a class property and define that property in the constructor whenever the class is instantiated. But since the LogHelper class is instantiated as ObjectFactory.GetInstance<ILogger>(). I am not able call the constructor in which I can pass the filename.
Unfortunately the way you are going about this is a little bit self-defeating. Your classes only know about ILogger, not any particular implementation of ILogger. That's good - it means that the implementation could write to a file, a SQL table, or anything.
But if your class only knows about ILogger, not the implementation, then how does your class know that the logger needs a file path? If you change your method signatures in ILogger to contain a file path, then two things happen.
It becomes impossible to have any implementation of ILogger that doesn't write to a file (unless it ignores the file path, which would be really weird.)
Now that class that calls the logger has to know a file path. Where will that class get a file path from? Will it be stored in the class? In that case you end up with a class that doesn't work unless it's part of an assembly executing on a computer where it can write to that exact file path.
Instead, the details of where and how to log should live somewhere in your ILogger implementation. That's closer to the Single Responsibility Principle. The class that calls ILogger isn't responsible for decisions about how ILogger works. It doesn't know and it doesn't want to know. It says "Here, take this and log it." The logger implementation is responsible for the rest.
I'd recommend scrapping the static ObjectFactory entirely and using the container to resolve and create all of your classes, including the logger and the classes that depend on it, but that's so broad that it's not really helpful. (It has been deprecated because it's a bad pattern. It's not even in the latest version of StructureMap.)
Everything above this is a recommendation. After this I'm offering an option that's not really recommendable, but requires less change and keeps your classes from knowing about file paths, because please don't do that ever.
One option - a halfway compromise - might be to register different named implementations of ILogger. You could modify your logger class to look like this:
public class FileLogger : ILogger
{
private readonly string _filePath;
public FileLogger(string filePath)
{
_filePath = filePath;
}
}
Now you can create multiple instances of that logger class, passing a different file path to each one. That way it's not a static property, which limits you to only having one file path.
Then you could register your implementations like this.
ObjectFactory.Initialize(
request =>
{
request.For<ILogger>().Singleton()
.Use<FileLogger>(() => new FileLogger("some path")).Name = "LoggerOne";
request.For<ILogger>().Singleton()
.Use<FileLogger>(() => new FileLogger("some other path")).Name = "LoggerTwo";
});
Now your class can say which logger it wants, like this:
var logger = ObjectFactory.GetNamedInstance<ILogger>("LoggerOne");
But please don't really do that either. It's more than I can really describe here in great detail, but take a look at dependency injection so that your classes really only know about ILogger and don't know or care which implementation they get and don't tell it anything about how to do its job.
You are using your logger as a singleton, so you are not creating an instance each time you call ObjectFactory.GetInstance<ILogger>();, you are simply getting a reference to the same logger instance all the time which is created once on first use.
If you want to write to a specific destination, then the best solution is to specify the destination in the Logging methods:
void LogError(string message,
Exception exception = null,
string destination = /*some adequate defualt value*/);
void LogMessage(string message,
string destination = /*some adequate defualt value*/);
Creating state information in your logger instance with a specific destination can be dangerous if you are using the logger concurrently from methods that are expecting and therefore setting different destinations; you can end up logging things where they are not supposed to.
Which brings up an important issue; because you are sharing the logger across your application (singleton) make sure its methods are safe to call concurrently if there is a possiblity that it will be called this way.

C# API library and logging to PowerShell's WriteVerbose()

I'm building a DLL in C# that I will be consuming with several different projects - so far, I know of a WPF application and a (binary) PowerShell module. Because the core business logic needs to be shared across multiple projects, I don't want the PowerShell module itself to contain the core logic. I'd just like to reference my primary library.
I'm struggling to figure out how to implement a clean logging solution in my core DLL that will be accessible via PowerShell's WriteVerbose() method. Without this, I can provide verbose output to PowerShell about PowerShell-specific things, but I can't provide any verbose output about "waiting for HTTP request" or other features that would be in the core DLL.
Here's a simple example of what I'm trying to do:
using System;
using System.Threading;
namespace CoreApp
{
public class AppObject
{
public AppObject() {}
public int DoStuffThatTakesForever()
{
// Assume logger is a logging object - could be an existing
// library like NLog, or I could write it myself
logger.Info("Doing step 1");
Thread.Sleep(5000);
logger.Info("Doing step 2");
Thread.Sleep(5000);
logger.Info("Doing step 3");
Random r = new Random();
r.Next(0, 10);
}
}
}
////////////////////////////////////////////////////////////
// Separate VS project that references the CoreApp project
using System.Management.Automation;
using CoreApp;
namespace CoreApp.PowerShell
{
[Cmdlet(VerbsCommon.Invoke, "ThingWithAppObject"]
[OutputType(typeof(Int32))]
public class InvokeThingWithAppObject : Cmdlet
{
[Parameter(Position = 0)]
public AppObject InputObject {get; set;}
protected override void ProcessRecord()
{
// Here I want to be able to send the logging phrases,
// "Doing step 1", "Doing step 2", etc., to PowerShell's
// verbose stream (probably using Cmdlet.WriteVerbose() )
int result = InputObject.DoStuffThatTakesForever();
WriteObject(result);
}
}
}
How can I provide verbose PowerShell verbose output without tightly binding the core library with the PowerShell module?
I'm definitely open to other solutions, but here's how I ended up solving it:
In the core library, I created an ILogger interface with methods for Info, Verbose, Warn, etc. I created a DefaultLogger class that implemented that logger (by writing everything to the attached debugger), and I gave this class a static singleton instance.
In each method that I wanted logged, I added an optional ILogger parameter, and added a line to use the default logger if necessary. The method definitions now look like this:
public int DoSomething(ILogger logger = null)
{
logger = logger ?? MyAppLogger.Singleton;
// Rest of the code
Random r = new Random();
return r.Next(0, 10);
}
I had to do this for each method because the PSCmdlet.WriteVerbose() method expects to be called from the currently running cmdlet. I couldn't create a persistent class variable to hold a logger object because each time the user ran a cmdlet, the PSCmdlet object (with the WriteVerbose method I need) would change.
Finally, I went back to the PowerShell consumer project. I implemented the ILogger class in my base cmdlet class:
public class MyCmdletBase : PSCmdlet, ILogger
{
public void Verbose(string message) => WriteVerbose(message);
public void Debug(string message) => WriteDebug(message);
// etc.
}
Now it's trivial to pass the current cmdlet as an ILogger instance when calling a method from the core library:
[Cmdlet(VerbsCommon.Invoke, "ThingWithAppObject"]
[OutputType(typeof(Int32))]
public class InvokeThingWithAppObject : MyCmdletBase
{
[Parameter(Mandatory = true, Position = 0)]
public AppObject InputObject {get; set;}
protected override void ProcessRecord()
{
int result = InputObject.DoSomething(this);
WriteObject(result);
}
}
In a different project, I'll need to write some kind of "log adapter" to implement the ILogger interface and write log entries to NLog (or whatever logging library I end up with).
The only other hiccup I ran into is that WriteVerbose(), WriteDebug(), etc. cannot be called from a different thread than the main thread the cmdlet is running on. This was a significant problem, since I'm making async Web requests, but after banging my head on the wall I decided to just block and run the Web requests synchronously instead. I'll probably end up implementing both a synchronous and an async version of each Web-based function in the core library.
This approach feels a bit dirty to me, but it works brilliantly.

Injecting Internal Classes into Azure WebJob Functions

Is there any way for the default Functions class that comes in WebJob projects to be internal? We are using a job activator to inject via Unity some dependencies that are internal, which requires that the Functions class also be internal. When running the web job, we are seeing the following error:
No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
When we make all the dependencies public, it works fine, so I know there's nothing wrong with my triggers or my job host config.
Here's my Program class:
class Program
{
static void Main()
{
var config = new JobHostConfiguration
{
JobActivator = new Activator(new UnityContainer())
};
config.UseServiceBus();
var host = new JobHost(config);
host.RunAndBlock();
}
}
Here's a simplified version of my Functions class:
internal class Functions
{
private readonly IMyInternalDependency _dependency;
public Functions(IMyInternalDependency dependency)
{
_dependency = dependency;
}
public function DoSomething([ServiceBusTrigger("my-queue")] BrokeredMessage message)
{
// Do something with the message
}
}
You must make the Functions class public. That appears to be just how Azure WebJobs works. You don't need to expose your concrete internal classes publicly. Just the interfaces:
public interface IDoStuffPublically
{
void DoSomething();
}
interface IDoStuffInternally
{
void DoSomething();
void DoSomethingInternally();
}
class DoStuff : IDoStuffPublically, IDoStuffInternally
{
public void DoSomething()
{
// ...
}
public void DoSomethingInternally()
{
// ...
}
}
And then your Functions class:
public class Functions
{
public Functions(IDoStuffPublically stuff)
{
_stuff = stuff;
}
private IDoStuffPublically _stuff;
// ...
}
And Unity will do something like this:
var job = new Functions(new DoStuff());
Dave commented:
It's frustrating that I cannot simply set the internals visible to the WebJob SDK...
You might be able to accomplish this... miiiiiiiiiight be able to...
There is a way for an assembly or executable to grant another assembly the permission to access internal members. I've done this before on a class library to allow my unit tests to call internal methods on a class as part of setting up a unit test.
If you know which assembly in Azure WebJobs actually creates the instance of your Functions class, and the assembly that invokes the methods on that class, you could white list those assemblies.
Crack open AssemblyInfo.cs and add one or more lines:
[assembly: InternalsVisibleTo("Microsoft.Azure.Something.Something")]
Reference: InternalsVisibleToAttribute class
Related reading: .Net Tips – using InternalsVisibleTo attribute to help testing non-public methods
I'm not sure which assemblies you would need to add, though.
When using Triggers with the Webjob SDK, you never register the functions to be executed.
When the jobhost starts (new JobHost(config).RunAndBlock()), it discoverers the functions to be executed based on parameter attributes.
Let's have a look at your code:
var config = new JobHostConfiguration
{
JobActivator = new Activator(new UnityContainer())
};
config.UseServiceBus();
Because you specify that you want to use servicebus, when the jobhost starts, it will discover and register (index) all the functions that have a parameter with the ServiceBusTrigger attribute.
I assume that the SDK uses something like MemberInfo.GetCustomAttributes to index the functions so don't know if it is (possible and) easy to get attributes from an internal class.

UnityContainer.RegisterType does not get used when put in a Static Constructor

This is an example console application (it will run fine after adding the Unity NugGet package) that seems to show a bug in Unity:
using System;
using Microsoft.Practices.Unity;
class GC { public static UnityContainer Container = new UnityContainer();}
class Program
{
static void Main(string[] args)
{
GC.Container.RegisterType<MyView>();
var myView = GC.Container.Resolve<MyView>();
Console.ReadLine();
}
}
public class MyClassDesign: MyClass{}
public class MyClass: VMBase<MyClass, MyClassDesign>{}
public abstract class VMBase<TViewModel, TDesignVM> where TDesignVM:TViewModel
{
static VMBase()
{
if (!GC.Container.IsRegistered(typeof(TViewModel)))
GC.Container.RegisterType(typeof (TViewModel), typeof(TDesignVM));
}
}
public class MyView
{
public MyView(MyClass myClass)
{
Console.WriteLine("Bad: "+myClass.GetType().ToString());
Console.WriteLine("Good: "+GC.Container.Resolve<MyClass>().GetType());
}
}
The output is:
Bad: MyClass
Good: MyClassDesign
The resolved type is MyClass. But it should be MyClassDesign. (The static constructor runs prior to MyClass being resolved in the MyView class.)
How can I get Unity to allow me to setup my Mapping in the Static Constructor?
Note: When I changed this setup the UnityContainer with a file (instead of in code) it all works fine. But I would rather not be dependent on an external file for this. (I am making a reusable template that I don't want to have too many dependencies in.)
Why do you want to put the registration logic inside your view model at all? This couples your application code to the container which is never a good idea. Have a look at the concept of Composition roots.
All setup code for the DI container should be placed there.
This isnt really a bug with Unity. The issue is that the static ctor is not run until an instance is requested (at which point unity still does not know about MyClassDesign). Which means that Unity has already started creating an instance of MyClass to fulfill the request. Any subsequent calls to GC.Container.Resolve<MyView>(); will result in the output you expect. As Sebastian Weber suggests, putting all your setup code in a completely seperate location (so your classes are not dependent on a specific DI container) is the best option.

Categories

Resources