Share class code across multiple C# Libraries that reference each other - c#

I am trying to get my head around sharing common Log class across C# Libraries that reference each other. The problem is that I am confused as to which direction to choose.
Example C# Log class code
namespace MyLogger.Log
{
public class MyLogger
{
public void Error(string message)
{
var eventArgs = new LogGeneratedEventArgs();
eventArgs.Message = message;
eventArgs.Type = LogType.Error;
LogGenerated?.Invoke(this, eventArgs);
}
public void Info(string message)
{
var eventArgs = new LogGeneratedEventArgs();
eventArgs.Message = message;
eventArgs.Type = LogType.Info;
LogGenerated?.Invoke(this, eventArgs);
}
public event EventHandler<LogGeneratedEventArgs> LogGenerated;
}
public class LogGeneratedEventArgs : EventArgs
{
public string Message { get; set; }
public LogType Type { get; set; }
}
public enum LogType
{
Error, Info
}
}
Say I got 2 other Libraries
Library 1
Library 2
Both the libraries need to log information of their internal working and depend on each other. So I have a new project for the above Log management class. But I do not intend to create a new reference dependency just to handle logging.
If I create a standalone C# library for the class then I have to update the NuGet package for that Log class library whenever I create new versions of the other 2.
If I add the code of the Log class as "Add to Link" in Visual Studio I get a namespace conflict error when working with other projects that need both the libraries. Moreover, when working with large projects I get multiple namespace options for the same Log class.
How should I go about sharing the Code across the 2 Libraries without having to add new reference dependency and hitting conflicts? :)

Related

How to setup NLog with Sustainsys.Saml2

I have an ASP.Net Web Forms app where I just integrated Sustainsys.Saml2 library.
I've never used any sort of logging mechanism and I'm trying to figure out how to add or create an ILoggerAdapter for the library stated on their troubleshooting page.
I've decided to use NLog (please feel free to recommend a different one) and either I'm not understanding this well, or am not using the right keyword to search for what I need/want, or their isn't a lot of documentation on it.
Currently, I'm using the HttpModule version of Sustainsys.Saml2. Any other information available upon request.
Any help would be great.
Currently, I'm configuring the Sustainsys.Saml2 library through both web.config and the global.asax files. Here's the class my global.asax calls:
public class Saml2Config {
private static bool _alreadyInitialized;
private static readonly object Lock = new object();
public static void Initialize() {
if (_alreadyInitialized) {
return;
}
lock (Lock) {
if (_alreadyInitialized) {
return;
}
var domain = PageHelper.GetDomainURL(true);
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.EntityId.Id = $"{domain}/federation/Saml2";
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.ModulePath = "/federation/Saml2";
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.ReturnUrl = new Uri($"{domain}/mybarry");
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.PublicOrigin = new Uri($"{domain}");
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.Logger = new NullLoggerAdapter();
_alreadyInitialized = true;
}
}
}
The interface is pretty straightforward
public interface ILoggerAdapter
{
void WriteInformation(string message);
void WriteError(string message, Exception ex);
void WriteVerbose(string message);
}
I would implement it as follows:
public class NLogAdapter : ILoggerAdapter
{
private static Logger Logger = LogManager.GetLogger("Saml2");
public void WriteInformation(string message)
{
Logger.Info(message);
}
public void WriteError(string message, Exception ex)
{
Logger.Error(ex, message);
}
public void WriteVerbose(string message)
{
Logger.Debug(message);
}
}
And finally set it:
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.Logger = new NLogAdapter();
The ILoggerAdapter contains methods for different loglevels. Make an adapter class that implements ILoggerAdapter and writes to NLog. Then set SPOptions.Logger to an instance of your adapter class.
If you want an example, you can check out the adapter for Asp.Net Core that logs to the Asp.Net Core logging system and is the default for the Sustainsys.Saml2.AspNetCore2 package: https://github.com/Sustainsys/Saml2/blob/master/Sustainsys.Saml2.AspNetCore2/AspNetCoreLoggerAdapter.cs
For the Sustainsys.Saml2.HttpModule library the default is the NullLoggerAdapter which simply discards any logs. Only reason to use it is to not have to nullcheck the Logger property everywhere it is used (that code was written before the ?. syntax was introduced.)

servicestack serverevents triggered by eventhandler/action

Context:
I am using the ServiceStack Framework (4.0.42) for my application. It is selfhosted and runs as a windows service. The main purpose is to give some devices the ability to communicate via web services (RESTful and ServerEvent).
For this I created a common interface for all types of devices which look like this (simplified):
public interface IDevice
{
string GetName();
bool IsConnected(string id);
event EventHandler<EventArgs> RaiseSomeEvent;
}
This interface is implemented in DLL’s one for each type of device.
My problem is that I can’t figure out how to forward the RaiseSomeEvent to notify a subscriber to ServerEvents.
I tried many different implementations, none of them worked. Most, it ended up, that at runtime, when the DeviceAdapter_RaiseSomeEvent is called, the ServerEvents instance is null.
I am running out of ideas now.
Here is the actual (simplified) Version:
public class ServiceInterface : Service
{
public IDevice DeviceAdapter { get; set; }
public IServerEvents ServerEvents { get; set; }
public IAppSettings AppSettings { get; set; }
public ServiceInterface(IDevice deviceAdapter)
{
DeviceAdapter = deviceAdapter;
DeviceAdapter.RaiseSomeEvent += DeviceAdapter_RaiseSomeEvent;
}
public void DeviceAdapter_RaiseSomeEvent(object sender, EventArgs e)
{
ServerEvents.NotifyAll("Something happend!");
}
and here the AppHost Class:
public class AppHost : AppSelfHostBase
{
public IDevice DeviceAdapter;
public AppHost()
: base("grob.MachineConnector.Service", typeof(ServiceInterface).Assembly)
{ }
public override void Configure(Funq.Container container)
{
this.Plugins.Add(new ServerEventsFeature());
switch (UsedAdapter)
{
case enAdapterTyp.DeviceTyp1:
DeviceAdapter = new DeviceTyp1();
break;
case enAdapterTyp.DeviceTyp2:
DeviceAdapter = new DeviceTyp2();
break;
default:
throw new AdapterTypException("Wrong or no Adaptertyp is configured:" + UsedAdapter.ToString());
}
container.Register(new ServiceInterface(DeviceAdapter));
}
Maybe it lies somewhere in the Funq. I am not sure what happening exactly with the DI, IoC, Autowiring stuff. I tried to write my own Plugin for the framework. I have no idea how to get the a valid instance of IServerEvents when a Event rises from my Device.
Maybe I did some general design faults. For OOP and C# I am at beginner level.
Any hints are very welcome.
The Service Dependencies are only available within the lifetime of a request, beyond that the Service and its dependencies are released/disposed. It's not clear from the event that it's only raised during the Request:
DeviceAdapter.RaiseSomeEvent += DeviceAdapter_RaiseSomeEvent;
You should also never register a Service as they're automatically registered and autowired by ServiceStack:
//Don't register Services
//container.Register(new ServiceInterface(DeviceAdapter));
Otherwise IServerEvents is just a normal Singleton dependency that's registered when the ServerEventsFeature Plugin is loaded.
Normally you'd just access it like any other dependency, where you'd just resolve it in the dependency that needs it, i.e:
container.Register<IDevice>(c => new DeviceTyp1 {
ServerEvents = c.Resolve<IServerEvents>()
});
Which will automatically inject the resolved IDevice into the Service dependencies:
public class ServiceInterface : Service
{
public IDevice DeviceAdapter { get; set; }
public object Any(Request request)
{
//DeviceAdapter also has access to IServerEvents
DeviceAdapter.Exec(request);
}
}
But if this event is not in reaction to a Service request then the event shouldn't be tied to a Service, i.e. you could just have the handler in the AppHost:
public override void Configure(Funq.Container container)
{
DeviceAdapter.RaiseSomeEvent += DeviceAdapter_RaiseSomeEvent;
}
public void DeviceAdapter_RaiseSomeEvent(object sender, EventArgs e)
{
var serverEvents = Container.Resolve<IServerEvents>();
serverEvents.NotifyAll("cmd.Handler", "Something happend!");
}
Please also see the documentation on Selectors so you know which selector the message should be sent with.
See this answer on different ways you can resolve IOC dependencies from outside of ServiceStack may also be helpful.

Write device platform specific code in Xamarin.Forms

I have the following Xamarin.Forms.ContentPage class structure
public class MyPage : ContentPage
{
public MyPage()
{
//do work to initialize MyPage
}
public void LogIn(object sender, EventArgs eventArgs)
{
bool isAuthenticated = false;
string accessToken = string.Empty;
//do work to use authentication API to validate users
if(isAuthenticated)
{
//I would to write device specific code to write to the access token to the device
//Example of saving the access token to iOS device
NSUserDefaults.StandardUserDefaults.SetString(accessToken, "AccessToken");
//Example of saving the access token to Android device
var prefs = Application.Context.GetSharedPreferences("MySharedPrefs", FileCreationMode.Private);
var prefsEditor = prefs.Edit();
prefEditor.PutString("AccessToken", accessToken);
prefEditor.Commit();
}
}
}
I would like to write platform specific code in the MyPage LogIn method to save the access token based on which device OS they are using my application on.
How do I only run device specific code when the user uses my application on their device?
This is a scenario which is easily resolved with dependency injection.
Have a interface with the desired methods on your shared or PCL code, like:
public interface IUserPreferences
{
void SetString(string key, string value);
string GetString(string key);
}
Have a property on your App class of that interface:
public class App
{
public static IUserPreferences UserPreferences { get; private set; }
public static void Init(IUserPreferences userPreferencesImpl)
{
App.UserPreferences = userPreferencesImpl;
}
(...)
}
Create platform-specific implementations on your target projects:
iOS:
public class iOSUserPreferences : IUserPreferences
{
public void SetString(string key, string value)
{
NSUserDefaults.StandardUserDefaults.SetString(value, key);
}
public string GetString(string key)
{
return NSUserDefaults.StandardUserDefaults.StringForKey(key);
}
}
Android:
public class AndroidUserPreferences : IUserPreferences
{
public void SetString(string key, string value)
{
var prefs = Application.Context.GetSharedPreferences("MySharedPrefs", FileCreationMode.Private);
var prefsEditor = prefs.Edit();
prefEditor.PutString(key, value);
prefEditor.Commit();
}
public string GetString(string key)
{
(...)
}
}
Then on each platform-specific project create an implementation of IUserPreferences and set it using either App.Init(new iOSUserPrefernces()) and App.Init(new AndroidUserPrefernces()) methods.
Finally, you could change your code to:
public class MyPage : ContentPage
{
public MyPage()
{
//do work to initialize MyPage
}
public void LogIn(object sender, EventArgs eventArgs)
{
bool isAuthenticated = false;
string accessToken = string.Empty;
//do work to use authentication API to validate users
if(isAuthenticated)
{
App.UserPreferences.SetString("AccessToken", accessToken);
}
}
}
Xamarin.Forms 2.3.4 introduced a new method for this:
if (Device.RuntimePlatform == Device.Android)
{
// Android specific code
}
else if (Device.RuntimePlatform == Device.iOS)
{
// iOS specific code
}
else if (Device.RuntimePlatform == Device.UWP)
{
// UWP specific code
}
There are also other platforms to choose from, you can type in Device. in Visual Studio and it will show you the options.
There are multiple answers, depending on what you want to achieve, and the kind of project you have:
Execute different Xamarin.Forms code on different platforms.
Use this e.g. if you want different font sizes on different platforms:
label.Font = Device.OnPlatform<int> (12, 14, 14);
Execute platform specific code in a shared (PCL) project
The common pattern is to use DI (dependency injection) for this. Xamarin.Forms provides a simple DependencyService for this, but use whatever you want.
Execute platform specific code in shared (Shared Asset Project) project
As the code is compiled per platform, you can wrap your platform specific code in #if __PLATFORM__ #endif and have all the code in the same file. The platform project should define __IOS__, __ANDROID__ and __WINDOWS_PHONE__. Note that a shared asset project containing Xaml and code won't work well for iOS on Xamarin.Studio, and that having compiler directives makes your code harder to read and to test.
Xamarin.Forms has a built-in dependency injector if you take a look at their guide in the developer area of their website (http://developer.xamarin.com/guides/cross-platform/xamarin-forms/dependency-service/)
There's also a wonderful library you can pull from NuGet/Github (https://github.com/aritchie/acr-xamarin-forms) that will handle the storage requirement you are looking for... take a look at the Settings service in there, it will even handle serialization of more complex objects.
This seems less about Xamarin.Forms and more about using defaults in a PCL. Check out James Montemagno's github repo for doing cross-platform defaults.
Then just call his static methods for setting/retrieving. The nuget package is Xam.Plugins.Settings.
It can be used like this:
using Refractored.Xam.Settings;
...
CrossSettings.Current.AddOrUpdateValue("AccessToken", accessToken);
var value = CrossSettings.Current.GetValueOrDefault<string>("AccessToken");

MEF not providing object

Update:
This is an mvc plugin project, using MEF to get the controllers and actions at run time. http://www.fidelitydesign.net/?p=104
I added a new project and in its class I added an export of a type that is already being composed.
[Export(typeof(IController)), ExportMetadata("Name", "Clocks")]
public class ClocksController : Controller
{
public XmlActionResult Index()
{
var p = DeviceLogic.GetUnassigned;
}
[Import(typeof(DeviceLogic))]
DeviceLogic DeviceLogic { get; set; }
}
This gets composed in another project:
[Export]
public class ImportControllerFactory : DefaultControllerFactory
{
[ImportMany]
private IEnumerable<PartFactory<IController, IControllerMetadata>> ControllerFactories;
}
Application Start
[ImportMany]
private IEnumerable<ImportControllerFactory> ControllerFactories;
Controller factories is null, until I actually compose the parts
container.ComposeParts(this);
thats working fine, so I decided to try and emulate this to get devicelogic to appear in the project im having trouble with.
I created an emptry interface (IEmpty) for testing and tried this:
[Export(typeof(IEmpty))]
public class RequestProcessor : IEmpty
{
[Import(typeof(DeviceLogic))]
DeviceLogic DeviceLogic { get; set; }
}
and in my applciation start added
[ImportMany]
private IEnumerable<IEmpty> TestMef;
This is filled with the one instance after composition, so this seems to have worked. My question is does anyone have any suggestions as to why devicelogic is null in requestprocessor but not in clocksController.
You need to call MEF's SatisfyImportsOnce method after your instantiation :
YourMEFContainter.SatisfyImportsOnce(dataTransfer)

Unable to access a new class added to a class library

I have a class library that I added another class to that no matter what I try it will not be available in the project that I am referencing the library from. I have no problem with the original class I created in this library referencing and using.
I have tried all of the below:
Cleaning the project solution
Save and rebuild both the debug and release
Closing the project and reopening
Steps one through three on the library project I'm tyring to reference
In the project that I want to reference the library from I have tried loading the .dll form the bin/release folded, and the main library project .dll in the obj/release folder. Neater have made a difference because I still cannot get to the new class I added to the library. I am referencing the DotNetOpenAuth_Library.dll from the release folded in the bin.
If this makes a difference I'm using VS 2012 Express for Web that I downloaded last week.
The class I added to my library that has no build errors is:
namespace DotNetOpenAuth_Library
{
class EmbeddedResourceUrlService : IEmbeddedResourceRetrieval
{
private static string pathFormat = "{0}/Resource/GetWebResourceUrl? assemblyName= {1}&typeName={2}&resourceName={3}";
//private static string pathFormat = "{0}/Resource/GetWebResourceUrl";
public Uri GetWebResourceUrl(Type someTypeInResourceAssembly, string manifestResourceName)
{
if (manifestResourceName.Contains("http"))
{
return new Uri(manifestResourceName);
}
else
{
var assembly = someTypeInResourceAssembly.Assembly;
// HACK
string completeUrl = HttpContext.Current.Request.Url.ToString();
string host = completeUrl.Substring(0,
completeUrl.IndexOf(HttpContext.Current.Request.Url.AbsolutePath));
var path = string.Format(pathFormat,
host,
HttpUtility.UrlEncode(assembly.FullName),
HttpUtility.UrlEncode(someTypeInResourceAssembly.ToString()),
HttpUtility.UrlEncode(manifestResourceName));
return new Uri(path);
}
}
}
}
Put public in front of the class definition. If the class is marked internal1 it can only be accessed by other classes within the same assembly2.
namespace DotNetOpenAuth_Library
{
public class EmbeddedResourceUrlService : IEmbeddedResourceRetrieval
{
//(snip)
}
}
Here is a MSDN link explaining access modifiers.
1: If you do not put a modifier in front of the class it will default to internal.
2: unless you mark the other assembly a friend assembly
It looks to me like the problem is just the lack of an access modifier. By default the c# compiler treats classes as internal. It should work if you change the declaration to
public class EmbeddedResourceUrlService : IEmbeddedResourceRetrieval
The class EmbeddedResourceUrlService is private, use public modifier
namespace DotNetOpenAuth_Library
{
// make class public
public class EmbeddedResourceUrlService : IEmbeddedResourceRetrieval
{
private static string pathFormat = "{0}/Resource/GetWebResourceUrl? assemblyName= {1}&typeName={2}&resourceName={3}";
//private static string pathFormat = "{0}/Resource/GetWebResourceUrl";
public Uri GetWebResourceUrl(Type someTypeInResourceAssembly, string manifestResourceName)
{
if (manifestResourceName.Contains("http"))
{
return new Uri(manifestResourceName);
}
else
{
var assembly = someTypeInResourceAssembly.Assembly;
// HACK
string completeUrl = HttpContext.Current.Request.Url.ToString();
string host = completeUrl.Substring(0,
completeUrl.IndexOf(HttpContext.Current.Request.Url.AbsolutePath));
var path = string.Format(pathFormat,
host,
HttpUtility.UrlEncode(assembly.FullName),
HttpUtility.UrlEncode(someTypeInResourceAssembly.ToString()),
HttpUtility.UrlEncode(manifestResourceName));
return new Uri(path);
}
}
}
}
even if then the class does not shows up (has happended to a couple time)
clean solution
delete all bin folder from both project
rebuilt all
and error wont be there

Categories

Resources