NLog Custom Layout Renderer Integer - layout

How do you get an integer value to come from a custom layout renderer?
I am getting an exception when trying to use a custom layout renderer to set a property of a target that expects an integer. By stepping through the code, it looks like custom layout renderers are replaced with their values at the point of the log entry being written to the target. The exception thrown is happening when the logger object is created - and presumably when the NLog.config is processed and when it sees the reference to my custom layout renderer instead of an integer, the exception is thrown.
This is the custom layout renderer:
[LayoutRenderer("buffer-size")]
public class BufferSizeLayoutRenderer : LayoutRenderer
{
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
int BufferSize=150; // would actually read from externally managed settings
builder.Append(BufferSize);
}
}
I have the extension assembly registered in the NLog.config.
The reference to the custom layout renderer is in the BufferingWrapper target like this:
<target xsi:type="BufferingWrapper"
name="InfoBufferingTarget"
bufferSize="${buffer-size}"
flushTimeout="60000"
slidingTimeout="true">
And when the line of code executes that creates the logger object, this exception is thrown:
NLog.NLogConfigurationException was unhandled by user code
HResult=-2146233088
Message=Error when setting property 'BufferSize' on BufferingWrapper Target[InfoBufferingTarget]()
Source=NLog
StackTrace:
at NLog.Internal.PropertyHelper.SetPropertyFromString(Object o, String name, String value, ConfigurationItemFactory configurationItemFactory)
at NLog.Config.XmlLoggingConfiguration.ConfigureObjectFromAttributes(Object targetObject, NLogXmlElement element, Boolean ignoreType)
at NLog.Config.XmlLoggingConfiguration.ParseTargetElement(Target target, NLogXmlElement targetElement)
at NLog.Config.XmlLoggingConfiguration.ParseTargetsElement(NLogXmlElement targetsElement)
at NLog.Config.XmlLoggingConfiguration.ParseNLogElement(NLogXmlElement nlogElement, String baseDirectory)
at NLog.Config.XmlLoggingConfiguration.ParseTopLevel(NLogXmlElement content, String baseDirectory)
at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
at NLog.Config.XmlLoggingConfiguration..ctor(String fileName)
at NLog.LogFactory.LoadLoggingConfiguration(String configFile)
at NLog.LogFactory.get_Configuration()
at NLog.LogFactory.GetLogger(LoggerCacheKey cacheKey)
at NLog.LogFactory.GetLogger(String name)
at NLog.LogManager.GetCurrentClassLogger()
at MyCompany.NLogRepository..ctor() in c:\Source\NLogRepository.cs:line 19
at MyCompany.Controllers.LogController.Post(Data data) in c:\Source\LogController.cs:line 21
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClassc.<GetExecutor>b__6(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
InnerException:
HResult=-2146233088
Message=${buffer-size} is not a valid value for Int32.
Source=System
StackTrace:
at System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
at System.ComponentModel.TypeConverter.ConvertFromInvariantString(String text)
at NLog.Internal.PropertyHelper.TryTypeConverterConversion(Type type, String value, Object& newValue)
at NLog.Internal.PropertyHelper.SetPropertyFromString(Object o, String name, String value, ConfigurationItemFactory configurationItemFactory)
InnerException: System.FormatException
HResult=-2146233033
Message=Input string was not in a correct format.
Source=mscorlib
StackTrace:
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.ComponentModel.Int32Converter.FromString(String value, NumberFormatInfo formatInfo)
at System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
InnerException:
This exception is thrown before the code in the custom layout renderer is ever executed.
My ultimate goal - I need to be able to modify NLog settings at runtime without overwriting the NLog.config, which in my case would require a full application deployment. I want to be able to tweak the BufferingWrapper settings and see the effect on performance. If there's another way to accomplish this without using custom layout renderers and without completely creating the NLog configuration in code, let me know.
Any help would be greatly appreciated.

The property needs to be a Layout and hence a string.
You need a render and then a parse it. E.g.
Layout l = "${..}"
var size = Int.Parse(l.Render(logEventInfo)) //todo better checking

Related

nUnit testing a controller extension method

UX controls framework I'm using requires an extension method on MVC controllers. A null object reference is thrown when nUnit tries to call that method (used in order to package a partial view into Json).
The author of the framework suggested calling that method through an interface, however that just postpones the null error.
Is there a way to test the ActionResult from a controller that uses an extension method?
The Controller Create() method returns the resulting partial from the extension method:
return Json(new { Content = viewRender.RenderPartialView(this, "ListItems/SimpleSyllabi", new[] { nS }) });
The extension method signature is
public static string RenderPartialView(this Controller controller, string viewName, object model = null, bool removeWhiteSpace = true);
Error is a simple:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Result StackTrace:
at System.Web.Mvc.VirtualPathProviderViewEngine.FindPartialView(ControllerContext controllerContext, String partialViewName, Boolean useCache)
at System.Web.Mvc.ViewEngineCollection.<>c__DisplayClass2.<FindPartialView>b__0(IViewEngine e)
at System.Web.Mvc.ViewEngineCollection.Find(Func`2 lookup, Boolean trackSearchedPaths)
at System.Web.Mvc.ViewEngineCollection.FindPartialView(ControllerContext controllerContext, String partialViewName)
at Omu.AwesomeMvc.ControllerExtensions.RenderView(Controller controller, String viewName, Object model, String master, Boolean partial, Boolean removeWhiteSpace)
at Omu.AwesomeMvc.ControllerExtensions.RenderPartialView(Controller controller, String viewName, Object model, Boolean removeWhiteSpace)
at Flipprs.nUnitHelpers.Awesome.ViewRender.RenderPartialView(Controller controller, String viewName, Object model, Boolean removeWhiteSpace) in A:\Stephan\Source\Workspaces\AchievementCards\Develop-Payment(v0.0.11.0)\Flipprs.Web\Helpers\Awesome\nUnitHelpers.cs:line 17
at Flipprs.Controllers.SyllabusAjaxListController.Create(SyllabusCreateViewModel scvm) in A:\Stephan\Source\Workspaces\AchievementCards\Develop-Payment(v0.0.11.0)\Flipprs.Web\Controllers\SyllabusAjaxListController.cs:line 217
at Flipprs.Tests.Controllers.SyllabusAjaxListControllerTest.SyllabusAjaxListController_CreatePUT_ReturnsJson(String HTTPreqAUEmail) in A:\Stephan\Source\Workspaces\AchievementCards\Develop-Payment(v0.0.11.0)\Flipprs.Tests\Controllers\SyllabusAjaxListControllerTest.cs:line 484
Result Message: System.NullReferenceException : Object reference not set to an instance of an object.
The Integration Test 'Setup':
private IViewRender viewRender;
viewRender = new ViewRender();
controller = new SyllabusAjaxListController(viewRender, photoPlaceholderService, activityService, syllabusService,
userService, organisationService, userManager);
Then in the test (excerpts)
[Test, Sequential]
public void SyllabusAjaxListController_CreatePUT_ReturnsJson()
{
ActionResult result_ar = controller.Create(validModel);
JsonResult result = result_ar as JsonResult;
}
Integration Test Mocks
Mock<ControllerContext> controllerContext;
Mock<HttpContext> httpContext;
Mock<HttpContextBase> contextBase;
Mock<HttpRequestBase> httpRequest;
Mock<HttpResponseBase> httpResponse;
Mock<IIdentity> identity;
Mock<IPrincipal> principal;
Mock<GenericPrincipal> genericPrincipal;
It appears the subject under test may be tightly coupled to 3rd party implementation concerns that make testing it in isolation difficult.
I suggest mocking the view render abstraction referred to in your original statement
public interface IViewRender {
string RenderPartialView(Controller controller, string viewName, object model = null, bool removeWhiteSpace = true);
}
to return a string when invoked so that the method under test can flow to completion and you can assert you expected behavior.
//Arrange
//...
var viewRenderMock = new Mock<IViewRender>(); //Using Moq mocking framework
viewRenderMock
.Setup(_ => _.RenderPartialView(It.IsAny<Controller>(), It.IsAny<string>(), It.IsAny<object>(), true))
.Returns("some fake view string");
//...
var controller = new SyllabusAjaxListController(viewRenderMock.Object,...) {
//...
};
//Act
var result = controller.Create(validModel) as JsonResult;
//Assert
result.Should().NotBeNull(); //FluentAssertions
//...other assertions.

Mvvcross WithFallback on xamarin ios

i'm using MvvmCross on xamarin iOS. I'm using fluent for the bindings on the ViewModel and json. I wanted to try the WithFallback() function, but when the property on my ViewModel (string in this case), comes null or empty, it doesn't do anything. I tried this:
//This works
this.BindLanguage(Header1, "Title");
/* This works when vm.Message is not null or empty,
/* else print nothing, but don't call the WithFallback function
*/
set.Bind(myLbl).For(view => view.Text).To(vm => vm.Message).WithFallback("Something");
set.Apply();
And another question is how i can bind that fallback with a property of the viewmodel or json. Thanks a lot!
Fallback will only be used if the binding fails, not if the property exists and is null or whatever.
You can read more about this in the official documentation.
In your case, I would suggest you use a ValueConverter, something like this will work:
public class MyValueConverter : MvxValueConverter<string, string>
{
protected override string Convert(string value, Type targetType, object parameter, CultureInfo culture)
{
return !string.IsNullOrEmpty(value) ? value : "Something";
}
protected override string ConvertBack(string value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then your binding:
set.Bind(myLbl).For(view => view.Text).To(vm => vm.Message).WithConversion<MyValueConverter>();

Why this line [isLocalValueSet() ? getLocalValue(): ...] instead of [isLocalValueSet() ? getValue(): ...] in UIInput class?

I have gone through this, but the answer is not very clear to me. Hence asking,
For the validate method of the class UIInput, we have this (Marking only those lines which are related to the question)
public void validate(FacesContext context) {
Object submittedValue = getSubmittedValue(); // LINE 958
newValue = getConvertedValue(context, submittedValue); // LINE 976
validateValue(context, newValue); // LINE 983
if (isValid()) { // LINE 987
Object previous = getValue();
setValue(newValue); // LINE 989
setSubmittedValue(null);
}
}
If both Conversion & Validation succeeds, then isValid() returns true.
The component's local value is then set - setValue(newValue), indicated by the flag setLocalValueSet(true)
After that, the submitted value is set to null - setSubmittedValue(null)
If you look at the code for this setValue(...) method of UIInput, it is overridden,
#Override
public void setValue(Object value) {
super.setValue(value);
// Mark the local value as set.
setLocalValueSet(true);
}
So from LINE 989, the call delegated to this above setValue(...).
If you look at this method,
#Override
public Object getValue() {
return isLocalValueSet() ? getLocalValue() : super.getValue();
}
If the local value was set by setValue(...), indicated by the flag setLocalValueSet(true),
why is this returning the getLocalValue()?
I mean,
isLocalValueSet() ? getLocalValue() : ....
Why is it not
isLocalValueSet() ? getValue() : ....
As seen through above, my confusion is regarding getValue() & getLocalValue() methods. Furthermore, in which case Object previous = getValue(); will be not null?
If the local value was set by setValue(...), indicated by the flag setLocalValueSet(true), why is this returning the getLocalValue()?
I think it's helpful to read javadoc of ValueHolder interface.
Object getLocalValue()
Return the local value of this UIComponent (if any), without evaluating any associated ValueExpression.
Object getValue()
Gets the value of this UIComponent. If validation failed, as indicated by FacesContext.isValidationFailed() returning true, always return the local value. Otherwise, first, consult the local value property of this component. If non-null return it. If null, see if we have a ValueExpression for the value property. If so, return the result of evaluating the property, otherwise return null.
void setValue(Object value)
Set the value of this UIComponent (if any).
Note my emphasis on "without".
In other words, getLocalValue() and setValue() form a true getter/setter pair, basically referring component's own instance variable, not the bean property behind any expression specified in component's value attribute such as value="#{bean.value}".
The getValue() method is implemented in such way that it auto-evaluates any associated ValueExpression when validation hasn't failed (yet) and the local value is null. This is undesireable when the (converted) submitted value is actually null and the component is still busy processing the validations phase and the model values haven't been updated yet.
Simply put, if getValue() were used instead of getLocalValue(), then the case "user removed (non-required) input value" would fail as getValue() returns the initial model value.
Furthermore, in which case Object previous = getValue(); will be not null?
When there's an initial value in the model.

Entity Framework 4.1 - Dynamic Eager Loading

I have an Entity Framework model (some properties have been excluded to keep it simple):
public class Media
{
public int MediaID { get; set; }
public ICollection<Track> Tracks { get; set; }
public ICollection<RelatedMedia> RelatedMedias { get; set; }
}
I then have my DbContext:
public class MediaServiceContext : DbContext
{
public DbSet<Media> Medias { get; set; }
}
I can then retrieve data using the following, and it works great:
public Media Media_Get(int id)
{
using (MediaServiceContext mc = new MediaServiceContext())
{
return mc.Medias.Include("Tracks").Include("RelatedMedias").Single(m => m.MediaID == id);
}
}
My question is, I may not want to load one or both of the related entities in some cases, depending on which part of my application is calling this code; how can I make the Includes dynamic?
I have tried this:
public Media Media_Get(int id, bool includeRelated, bool includeTracks)
{
using (MediaServiceContext mc = new MediaServiceContext())
{
IQueryable<Media> query = mc.Medias;
if (includeRelated)
query = query.Include("RelatedMedias");
if (includeTracks)
query = query.Include("Tracks");
return query.Single(m => m.MediaID == id);
}
}
...but I get a 'Specified cast in not valid' exception.
I have also tried this proposed solution, but it produces a 'unable to cast DbQuery to ObjectQuery' exception. Changing the extension method in the linked solution from '(ObjectQuery)source' to '(DbQuery)source' then causes the same 'Specified cast in not valid' exception.
I have hunted high and low for a solution on this but with no luck. Any help would be much appreciated.
Amendment - Here's the stack trace:
at System.Data.SqlClient.SqlBuffer.get_Int64()
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Coordinator.HasNextElement(Shaper shaper)
at System.Data.Common.Internal.Materialization.Shaper`1.RowNestedResultEnumerator.MoveNext()
at System.Data.Common.Internal.Materialization.Shaper`1.ObjectQueryNestedEnumerator.TryReadToNextElement()
at System.Data.Common.Internal.Materialization.Shaper`1.ObjectQueryNestedEnumerator.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
at API.Areas.V1.Models.RetailerManager.Media_Get(Int32 id, String retailerKey, Boolean includeLicenses, Boolean includeProperties, Boolean includeRelated, Boolean includeTracks) in C:\Users\garth\Documents\Development\WebApplications\api\Areas\V1\Models\RetailerManager.cs:line 28
at API.Areas.V1.Controllers.RetailerController.Media(Nullable`1 id, String httpVerb, Boolean includeLicenses, Boolean includeProperties, Boolean includeRelated, Boolean includeTracks) in C:\Users\garth\Documents\Development\WebApplications\api\Areas\V1\Controllers\RetailerController.cs:line 25
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
Your stack trace shows that .SingleOrDefault() caused this exception, but I don't see .SingleOrDefault() in your code.
I do see this:
return query.Single(m => m.MediaID == id);
Is it possible that Media.MediaID is a long and not an int?
Update
As another alternative to answer your original question, I answered a question a couple of weeks ago in relation to this. The sample code in my answer has to do with dynamic order by, but we use a very similar pattern for dynamic eager loading (see the first comment after my answer).
Instead of a method signature like this:
public Media Media_Get(int id, bool includeRelated, bool includeTracks)
Your signature would look more like this:
public Media Media_Get(MediaGetter mediaGetter)
...and you would use it like this:
var media = someInstance.Media_Get(
new MediaGetter { ID = id, }
.EagerLoad(m => m.Tracks)
.EagerLoad(m => m.RelatedTracks)
);

Handling Serialization Exceptions in ServiceStack

I am using ServiceStack to create a service which accepts request from and HTML form (POSTed). One of the DTO properties is an Enum, and when the input doesn't match the Enum members, I get the following exception:
Error occured while Processing Request: KeyValueDataContractDeserializer: Error converting to type: Requested value 'MyValue' was not found.
System.Runtime.Serialization.SerializationException: KeyValueDataContractDeserializer: Error converting to type: Requested value 'MyValue' was not found. ---> System.ArgumentException: Requested value 'MyValue' was not found.
at System.Enum.TryParseEnum(Type enumType, String value, Boolean ignoreCase, EnumResult& parseResult)
at System.Enum.Parse(Type enumType, String value, Boolean ignoreCase)
at ServiceStack.ServiceModel.Serialization.StringMapTypeDeserializer.PopulateFromMap(Object instance, IDictionary`2 keyValuePairs)
How can I intercept this exception and handle it myself in my service code?
There are a couple of ways to handle this situation:
You can make the DTO Enum property a string (since everything can successfully deserialize into a string :) and then convert that yourself manually i.e.
using ServiceStack.Common; //ToEnum<> is an extension method
public class RequestDto
{
public string EnumString { get; set; }
}
public override object OnGet(RequestDto request)
{
MyEnum defaultValue = MyEnum.None;
try {
defaultValue = request.EnumString.ToEnum<MyEnum>();
} catch {}
}
The other alternative is to completely remove it from the request DTO and get value manually from the IHttpRequest Context like:
public class RequestDto {}
public override object OnGet(RequestDto request)
{
MyEnum enumValue = MyEnum.DefaultValue;
try {
var enumStr = base.RequestContext.Get<IHttpRequest>().QueryString["EnumString"];
enumValue = enumStr.ToEnum<MyEnum>();
} catch {}
}
I generally discourage the use of enums on DTOs for many reasons, the primary one being on XML/SOAP endpoints the XSD treats them as a restricted set of values which is a pain in when trying iteratively to evolve your web services as you will need to re-gen the clients to add a new value.
By convention the way I deal with it is to have all enums as strings but provide some metadata on the DTO which points to the target type (which helps in VS.NET/R# navigation and metadata tools).
public class RequestDto
{
[References(typeof(MyEnum))]
public string EnumString { get; set; }
}

Resources