c++/cli custom exception - standard constructors - .net-4.0

Trying to avoid the FxCop warning 'Do not raise reserved exceptions' from a C++/CLI library so I decided to break down and write my own exception type.
[Serializable]
public ref class CaptureException : public Exception
{
public:
CaptureException() : Exception() {}
CaptureException(String^ message) : Exception(message) {}
CaptureException(String^ message, Exception^ inner) : Exception(message, inner) {}
protected:
CaptureException(System::Runtime::Serialization::SerializationInfo^ info, System::Runtime::Serialization::StreamingContext^ context) : Exception(info, context) {}
};
This doesn't compile stating
error C2664: 'System::Exception::Exception(System::String ^,System::Exception ^)' : cannot convert parameter 1 from 'System::Runtime::Serialization::SerializationInfo ^' to 'System::String ^'
I'm not sure why I'm getting this error. Does the C++/CLI not have the full exception class? I'm just trying to implement the standard constructors for my exception and in C# it looks like this and compiles fine.
[Serializable]
public class CaptureException : Exception
{
public DatabaseConnectionException() { }
public CaptureException (string message) : base(message) { }
public CaptureException (string message, Exception inner) : base(message, inner) { }
protected CaptureException (
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}

StreamingContext is a value type (i.e. a struct), so you'll want to remove the hat ^:
CaptureException(System::Runtime::Serialization::SerializationInfo^ info, System::Runtime::Serialization::StreamingContext context) : Exception(info, context)
{}

Related

Custom implementation of ILogger

In my project I often add prefixes to my log messages.
Currently I am doing this with
logger.LogDebug(prefix + " some message");
I thought it would be a good way to implement a custom logger where I set the prefix and the logger itself attaches it every time it logs something.
So I created my custom logger class and implemented the ILogger interface. But I do not understand how to use the
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
method to add the prefix (which is a member of the custom logger class).
My full code is:
public class CustomLogger : ILogger
{
private readonly ILogger _logger;
private string _logPrefix;
public CustomLogger(ILogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_logPrefix = null;
}
public ILogger SetLogPrefix(string logPrefix)
{
_logPrefix = logPrefix;
return this;
}
public IDisposable BeginScope<TState>(TState state)
{
return _logger.BeginScope(state);
}
public bool IsEnabled(LogLevel logLevel)
{
return _logger.IsEnabled(logLevel);
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
_logger.Log(logLevel, eventId, state, exception, formatter);
}
}
I think you should not call a _logger in a custom logger.
It would be a circular call on runtime and the result would be "prefix: prefix: prefix: prefix: prefix: prefix: prefix: prefix: ..."
Simply, you can create a simple logger and implement a log writter such as Console, database writter, log4net, ...
Now first, you should change your custom logger like below:
public class CustomLogger : ILogger
{
private readonly string CategoryName;
private readonly string _logPrefix;
public CustomLogger(string categoryName, string logPrefix)
{
CategoryName = categoryName;
_logPrefix = logPrefix;
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
string message = _logPrefix;
if (formatter != null)
{
message += formatter(state, exception);
}
// Implement log writter as you want. I am using Console
Console.WriteLine($"{logLevel.ToString()} - {eventId.Id} - {CategoryName} - {message}");
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
The second step, create a logger provider:
public class LoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName)
{
return new CustomLogger(categoryName, "This is prefix: ");
}
public void Dispose()
{
}
}
The third step, in Configure from Startup.cs:
loggerFactory.AddProvider(new MicroserviceLoggerProvider());
Personally, I think It's not a good way to do that, "prefix" will be duplicated a lot. Why don't you use Log Scopes instead?
public IActionResult GetById(string id)
{
TodoItem item;
using (_logger.BeginScope("Message attached to logs created in the using block"))
{
_logger.LogInformation(LoggingEvents.GetItem, "Getting item {ID}", id);
item = _todoRepository.Find(id);
if (item == null)
{
_logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);
return NotFound();
}
}
return new ObjectResult(item);
}
Output
info: TodoApi.Controllers.TodoController[1002]
=> RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block
Getting item 0
warn: TodoApi.Controllers.TodoController[4000]
=> RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block
GetById(0) NOT FOUND
Currently, you can't change the logging template, it's the limitation of built-in basic logging in Asp.net Core. For more powerful one, you can try Serilog, keep using ILogger interface and change some line of code in program.cs class
You should also look at this Benefits of Structured Logging vs basic logging
Implement an extensions for adding prefix to log records.
public static class LogExtensions
{
public static void PrefixLogDebug(this ILogger logger, string message, string prefix = "Edward", params object[] args)
{
logger.LogDebug($"{prefix} {message}");
}
}
Useage:
_log.PrefixLogDebug("Log From Prefix extension");
_log.PrefixLogDebug("Log From Prefix extension", "New Prefix");

When attaching agent to running process, bytebuddy transformer doesn't seem to take effect

The code of my program to be attached is as below.
public class Foo {
}
public class TestEntry {
public TestEntry() {
}
public static void main(String[] args) throws Exception {
try
{
while(true)
{
System.out.println(new Foo().toString());
Thread.sleep(1000);
}
}
catch(Exception e)
{}
}
}
What I attempt to do is to make Foo.toString() returns 'test' by using the following agent.
public class InjectionAgent {
public InjectionAgent() {
}
public static void agentmain(String args, Instrumentation inst) throws Exception
{
System.out.println("agentmain Args:" + args);
new AgentBuilder.Default()
.type(ElementMatchers.named("Foo"))
.transform(new AgentBuilder.Transformer() {
#Override
public Builder<?> transform(Builder<?> arg0, TypeDescription arg1,
ClassLoader arg2, JavaModule arg3) {
return arg0.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("test"));
}
}).installOn(inst);
}
public static void premain(String args, Instrumentation inst) throws Exception
{
System.out.println("premain Args:" + args);
new AgentBuilder.Default()
.type(ElementMatchers.named("Foo"))
.transform(new AgentBuilder.Transformer() {
#Override
public Builder<?> transform(Builder<?> arg0, TypeDescription arg1,
ClassLoader arg2, JavaModule arg3) {
return arg0.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("test"));
}
}).installOn(inst);
}
}
I notice that, it was successful when I using -javaagent way, whereas attach way failed, here is code for attach.
public class Injection {
public Injection() {
}
public static void main(String[] args) throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException, InterruptedException {
VirtualMachine vm = null;
String agentjarpath = args[0];
vm = VirtualMachine.attach(args[1]);
vm.loadAgent(agentjarpath, "This is Args to the Agent.");
vm.detach();
}
}
I tried to add AgentBuilder.Listener.StreamWriting.toSystemOut() to the agent, after attaching, the output of TestEntry shows
[Byte Buddy] DISCOVERY Foo [sun.misc.Launcher$AppClassLoader#33909752, null, loaded=true]
[Byte Buddy] TRANSFORM Foo [sun.misc.Launcher$AppClassLoader#33909752, null, loaded=true]
[Byte Buddy] COMPLETE Foo [sun.misc.Launcher$AppClassLoader#33909752, null, loaded=true]
Foo#7f31245a
Foo#6d6f6e28
Foo#135fbaa4
Foo#45ee12a7
Foo#330bedb4
==================================Update=====================================
I defined a public method 'Bar' in Foo like this
public class Foo {
public String Bar()
{
return "Bar";
}
}
and then I was trying to make Foo.Bar() returns "modified" in the following way:
public static void agentmain(String args, Instrumentation inst) throws Exception
{
System.out.println("agentmain Args:" + args);
premain(args, inst);
new AgentBuilder.Default()
.with(RedefinitionStrategy.RETRANSFORMATION)
.disableClassFormatChanges()
.with(AgentBuilder.Listener.StreamWriting.toSystemOut())
.type(ElementMatchers.named("Foo"))
.transform(new AgentBuilder.Transformer() {
#Override
public Builder<?> transform(Builder<?> arg0, TypeDescription arg1,
ClassLoader arg2, JavaModule arg3) {
return arg0.visit(Advice.to(InjectionTemplate.class).on(ElementMatchers.named("Bar")));
}
})
.installOn(inst);
}
static class InjectionTemplate {
#Advice.OnMethodExit
static void exit(#Advice.Return String self) {
System.out.println(self.toString() + " " + self.getClass().toString());
self = new String("modified");
}
}
but I got this error:
java.lang.IllegalStateException: Cannot write to read-only parameter class java.lang.String at 1
any suggestions?
It does not seem like you are using redefinition for your agent. You can activate it using:
new AgentBuilder.Default()
.with(RedefinitionStrategy.RETRANSFORMATION)
.disableClassFormatChanges();
The last part is required on most JVMs (with the notable exception of the dynamic code evolution VM, a custom build of HotSpot). It tells Byte Buddy to not add fields or methods, what most VMs do not support.
In this case, it is no longer possible to invoke the original implementation of a method what is however not required for your FixedValue. Typically, users of Byte Buddy take advantage of Advice when creating an agent that applies dynamic transformations of classes.

Error activating service - Ninject

I am getting the following error whenever I try to inject one of my service's dependency into the MVC controller:
Error activating IFeedService No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IFeedService into parameter svc of constructor of type FeedController
1) Request for FeedController
Suggestions:
1) Ensure that you have defined a binding for IFeedService.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
======================================================================
Here's how my code looks like:
ObjectFactory.cs
private static void RegisterServices(IKernel kernel)
{
// Contexts
kernel.Bind<IEntityObjectContext>().To<Entities>();
kernel.Bind<IAzureObjectContext>().To<AzureTableObjectContext>();
// Repositories
kernel.Bind<IEFRepository>().To<EFRepository>();
kernel.Bind<IAzureRepository>().To<AzureRepository>();
// Services
kernel.Bind<IFeedService>().To<FeedService>();
}
IEFRepository.cs
public interface IEFRepository : IDisposable
{
void SetContext(IEntityObjectContext context);
IQueryable<T> GetAll<T>() where T : class;
}
EFRepository.cs
public class EFRepository : IEFRepository
{
internal IEntityObjectContext context;
private Dictionary<Type, object> objectSets;
public EFRepository(IEntityObjectContext context)
{
this.context = context;
objectSets = new Dictionary<Type, object>();
}
public void SetContext(IEntityObjectContext context)
{
this.context = context;
}
}
IFeedService.cs
public interface IFeedService : IDisposable
{
IQueryable<FeedItem> GetPosts();
}
FeedService.cs
public class FeedService : IFeedService
{
private IEntityObjectContext _context;
private readonly IEFRepository _repo;
public FeedService(IEntityObjectContext context,
IEFRepository repo)
{
_context = context;
_repo = repo;
_repo.SetContext(_context);
}
public IQueryable<FeedItem> GetPosts()
{
using (_repo)
{
return _repo.GetAll<FeedItem>().Take(10);
}
}
}
FeedController.cs
public class FeedController : Controller
{
private readonly IFeedService _svc;
public FeedController(IFeedService svc)
{
_svc = svc;
}
}
As you can see, there are some nested dependency there in action. Not sure though, what needs to be added/removed for this bit to work.
Note: The error is thrown whenever I request the Feed/FetchFeed path. I also tried to comment out the FeedService's constructor portion to see if the nested dependencies are creating any problem, but again same error was thrown.
EDIT 1:
Rest of the code for the ObjectFactory.cs
class ObjectFactory
{
static ObjectFactory()
{
RegisterServices(kernel);
}
static IKernel kernel = new StandardKernel();
public static T GetInstance<T>()
{
return kernel.Get<T>();
}
private static void RegisterServices(IKernel kernel)
{
//...
}
}
EDIT 2:
I even tried to write a fairly basic service, but still the same error. Here's what I tried with:
public interface ITest
{
void CheckItOut();
}
public class Test : ITest
{
public void CheckItOut()
{
}
}
ObjectFactory.cs
kernel.Bind<ITest>().To<Test>();

Groovy compiler fails with unexpected token on readObject

My Gradle project has a mix of Java and Groovy classes. All source is under src/main/groovy. One of my Groovy classes contains a Map that I have created from reading a JSON string via JsonSlurper.parseText(). This class is marked Serializable.
To avoid a NotSerializableException, I have implemented my own writeObject() and readObject() methods, but my code is not compiling. I didn't find many Groovy examples, but various Java references and tutorials told me to use these signatures:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
My class looks like this:
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
class GroovyJSONMap implements Serializable {
private static final long serialVersionUID = 20150902L
Map myJSON = [:]
GroovyJSONMap() {
//no op
}
GroovyJSONMap(String json) {
if (json) {
try {
setJSON(json)
} catch (any) {
println "WHOOPS! Not a JSON object...."
myJSON = ["invalid": true]
}
}
}
GroovyJSONMap(Map json) {
if (json) {
setJSON(json)
}
}
final void setJSON(String json) {
myJSON = new JsonSlurper().parseText(json)
}
String getJSON() {
new JsonBuilder(myJSON).toString()
}
#Override
String toString() {
getJSON()
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
setJSON((String)in.readObject())
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(getJSON())
}
}
The compiler error:
:clean
:compileJava UP-TO-DATE
:compileGroovy
startup failed:
c:\path\to\src\main\groovy\GroovyJSONMap.groovy: 44: unexpected token: ObjectInputStream # line 110, column 29.
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
^
1 error
:compileGroovy FAILED
I have moved the readObject() method to various positions in the source, but it still is not compiling. The compiler does not complain about writeObject(), only readObject(). Why is my code not compiling?
The compiler points to ObjectOutputStream, but the problem is really at in.
The word in is a reserved word in Groovy and cannot be used for a variable or method name.
The solution is to rename in to any non-Groovy-reserved word, such as stream (also changed writeObject() for consistency):
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
setJSON((String)stream.readObject())
}
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.writeObject(getJSON())
}

AssemblyNeutral Attribute in ASp.net vnext

I recently come across AssemblyNeutral attribute of ASP.net vnext.
If I have to be specific then you will find that attribute usage in Logging respository. https://github.com/aspnet/logging
There are many other repository but this is simple one.
Now as per many blog if we use AssemblyNeutral attribute then that interface or type not tied with assembly so we can defined same interface with AssemblyNeutral attribute in some other framework that want same contract.
So create example I have created my own small logger library in ASP.net vnext class library project but It gives me type cast error.
namespace MyLogger
{
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILogger
{
void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter);
bool IsEnabled(LogLevel logLevel);
IDisposable BeginScope(object state);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILoggerFactory
{
ILogger Create(string name);
void AddProvider(ILoggerProvider provider);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILoggerProvider
{
ILogger Create(string name);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public enum LogLevel
{
Verbose = 1,
Information = 2,
Warning = 3,
Error = 4,
Critical = 5,
}
public class MyLogger : ILogger
{
public IDisposable BeginScope(object state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
System.IO.File.AppendAllText("C:\\Testlog.txt", "This is test log" + System.Environment.NewLine);
}
}
public class MyLoggerProvider : ILoggerProvider
{
private readonly Func<string, LogLevel, bool> _filter;
public MyLoggerProvider(Func<string, LogLevel, bool> filter)
{
_filter = filter;
}
public ILogger Create(string name)
{
return new MyLogger();
}
}
public static class MyLoggerExtentions
{
public static ILoggerFactory AddMyLogger(this ILoggerFactory factory, Func<string, LogLevel, bool> filter)
{
factory.AddProvider(new MyLoggerProvider(filter));
return factory;
}
}
}
Now I am trying to use in SampleApp ( Logging Repository SampleApp). You can see that it gives me Cast Error. Why so ?
The IDE doesn't handle assembly neutral interfaces defined in source properly as yet. That's why you're seeing errors.
I am partially agree with Visual Studio 2015 Preview IDE does not support AssemlbyNeutral attribute but Problem is somewhere else.
Actually when we defining Interface or Type again in custom assembly and if we want it support AssemblyNeutral then it must have same namespace as original interface.
In my sample I have done it wrong by putting interface in New Namespace.
I have updated the code and then I build in Visual Studio 2015 Preview It compile and even execute correctly.
So main thing to remember is "Put Assembly Neutral Interface and types in same namespace as it resides for original assembly".
Following is updated code.
namespace Microsoft.Framework.Logging
{
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILogger
{
void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter);
bool IsEnabled(LogLevel logLevel);
IDisposable BeginScope(object state);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILoggerFactory
{
ILogger Create(string name);
void AddProvider(ILoggerProvider provider);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public interface ILoggerProvider
{
ILogger Create(string name);
}
#if ASPNET50 || ASPNETCORE50
[Microsoft.Framework.Runtime.AssemblyNeutral]
#endif
public enum LogLevel
{
Verbose = 1,
Information = 2,
Warning = 3,
Error = 4,
Critical = 5,
}
}
namespace MyLogger
{
public class MyLogger : ILogger
{
public IDisposable BeginScope(object state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
System.IO.File.AppendAllText("C:\\Testlog.txt", "This is test log" + System.Environment.NewLine);
}
}
public class MyLoggerProvider : ILoggerProvider
{
private readonly Func<string, LogLevel, bool> _filter;
public MyLoggerProvider(Func<string, LogLevel, bool> filter)
{
_filter = filter;
}
public ILogger Create(string name)
{
return new MyLogger();
}
}
public static class MyLoggerExtentions
{
public static ILoggerFactory AddMyLogger(this ILoggerFactory factory, Func<string, LogLevel, bool> filter)
{
factory.AddProvider(new MyLoggerProvider(filter));
return factory;
}
}
}