Is it possible for Handlebars.Net to report errors/warnings for missing properties? - handlebars.net

Imagine that I have a template that requests {{Foo}} but that property does not exist on the given model. Can Handlebars.Net be configured to report this problem to me? To me it looks like it just silently inserts an empty string and proceeds.

The answer is yes:
var config = new HandlebarsConfiguration()
{
ThrowOnUnresolvedBindingExpression = true,
};
var handlebars = HandlebarsDotNet.Handlebars.Create(config);
var template = handlebars.Compile("Hello {{MissingProperty}}");
template(new object());
This will throw an exception telling you that MissingProperty was missing.
There is also the UnresolvedBindingFormatter which can be used if you don't want to throw an exception.
Related: The discussion on https://github.com/Handlebars-Net/Handlebars.Net/issues/143

Related

"Guid should contain 32 digits" serilog error with sql server sink

I am getting this error occasionally with the MSSQLServer sink. I can't see what's wrong with this guid. Any ideas? I've verified in every place I can find the data type of the source guid is "Guid" not a string. I'm just a bit mystified.
Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).Couldn't store <"7526f485-ec2d-4ec8-bd73-12a7d1c49a5d"> in UserId Column. Expected type is Guid.
The guid in this example is:
7526f485-ec2d-4ec8-bd73-12a7d1c49a5d
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
seems to match the template to me?
Further details:
This is an occasional issue, but when it arises it arises a lot. It seems to be tied to specific Guids. Most Guids are fine, but a small subset have this issue. Our app logs thousands of messages a day, but these messages are not logged (because of the issue) so it is difficult for me to track down exactly where the specific logs that are causing this error come from. However, we use a centralized logging method that is run something like this. This test passes for me, but it mirrors the setup and code we use for logging generally, which normally succeeds. As I said, this is an intermittent issue:
[Fact]
public void Foobar()
{
// arrange
var columnOptions = new ColumnOptions
{
AdditionalColumns = new Collection<SqlColumn>
{
new SqlColumn {DataType = SqlDbType.UniqueIdentifier, ColumnName = "UserId"},
},
};
columnOptions.Store.Remove(StandardColumn.MessageTemplate);
columnOptions.Store.Remove(StandardColumn.Properties);
columnOptions.Store.Remove(StandardColumn.LogEvent);
columnOptions.Properties.ExcludeAdditionalProperties = true;
var badGuid = new Guid("7526f485-ec2d-4ec8-bd73-12a7d1c49a5d");
var connectionString = "Server=(localdb)\\MSSQLLocalDB;Database=SomeDb;Trusted_Connection=True;MultipleActiveResultSets=true";
var logConfiguration = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.MSSqlServer(connectionString, "Logs",
restrictedToMinimumLevel: LogEventLevel.Information, autoCreateSqlTable: false,
columnOptions: columnOptions)
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information);
Log.Logger = logConfiguration.CreateLogger();
// Suspect the issue is with this line
LogContext.PushProperty("UserId", badGuid);
// Best practice would be to do something like this:
// using (LogContext.PushProperty("UserId", badGuid)
// {
Log.Logger.Information(new FormatException("Foobar"),"This is a test");
// }
Log.CloseAndFlush();
}
One thing I have noticed since constructing this test code is that the "PushProperty" for the UserId property is not captured and disposed. Since behaviour is "undefined" in this case, I am inclined to fix it anyway and see if the problem goes away.
full stack:
2020-04-20T08:38:17.5145399Z Exception while emitting periodic batch from Serilog.Sinks.MSSqlServer.MSSqlServerSink: System.ArgumentException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).Couldn't store <"7526f485-ec2d-4ec8-bd73-12a7d1c49a5d"> in UserId Column. Expected type is Guid.
---> System.FormatException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
at System.Guid.GuidResult.SetFailure(Boolean overflow, String failureMessageID)
at System.Guid.TryParseExactD(ReadOnlySpan`1 guidString, GuidResult& result)
at System.Guid.TryParseGuid(ReadOnlySpan`1 guidString, GuidResult& result)
at System.Guid..ctor(String g)
at System.Data.Common.ObjectStorage.Set(Int32 recordNo, Object value)
at System.Data.DataColumn.set_Item(Int32 record, Object value)
--- End of inner exception stack trace ---
at System.Data.DataColumn.set_Item(Int32 record, Object value)
at System.Data.DataRow.set_Item(DataColumn column, Object value)
at Serilog.Sinks.MSSqlServer.MSSqlServerSink.FillDataTable(IEnumerable`1 events)
at Serilog.Sinks.MSSqlServer.MSSqlServerSink.EmitBatchAsync(IEnumerable`1 events)
at Serilog.Sinks.PeriodicBatching.PeriodicBatchingSink.OnTick()
RESOLUTION
This issue was caused because someone created a log message with a placeholder that had the same name as our custom data column, but was passing in a string version of a guid instead of one typed as a guid.
Very simple example:
var badGuid = "7526f485-ec2d-4ec8-bd73-12a7d1c49a5d";
var badGuidConverted = Guid.Parse(badGuid); // just proving the guid is actually valid.
var goodGuid = Guid.NewGuid();
using (LogContext.PushProperty("UserId",goodGuid))
{
Log.Logger.Information("This is a problem with my other user {userid} that will crash serilog. This message will never end up in the database.", badGuid);
}
The quick fix is to edit the message template to change the placeholder from {userid} to something else.
Since our code was centralized around the place where the PushProperty occurs, I put some checks in there to monitor for this and throw a more useful error message in the future when someone does this again.
I don't see anything obvious in the specific code above that would cause the issue. The fact that you call PushProperty before setting up Serilog would be something I would change (i.e. set up Serilog first, then call PushProperty) but that doesn't seem to be the root cause of the issue you're having.
My guess, is that you have some code paths that are logging the UserId as a string, instead of a Guid. Serilog is expecting a Guid value type, so if you give it a string representation of a Guid it won't work and will give you that type of exception.
Maybe somewhere in the codebase you're calling .ToString on the UserId before logging? Or perhaps using string interpolation e.g. Log.Information("User is {UserId}", $"{UserId}");?
For example:
var badGuid = "7526f485-ec2d- 4ec8-bd73-12a7d1c49a5d";
LogContext.PushProperty("UserId", badGuid);
Log.Information(new FormatException("Foobar"), "This is a test");
Or even just logging a message with the UserId property directly:
var badGuid = "7526f485-ec2d-4ec8-bd73-12a7d1c49a5d";
Log.Information("The {UserId} is doing work", badGuid);
Both snippets above would throw the same exception you're having, because they use string values rather than real Guid values.

Can't get media image URL from Umbraco after upgrade

I have recently upgraded to 7.6.3 and I am having an issue retrieving media image URLs in my views. For testing purpposes, I added a new MediaPicker2 property for one of the nodes, set up a value for it and tried to get its value in my razor view:
var icon2 = Model.Content.GetProperty("icon2");
The object then looks like this:
Executing Model.Content.GetPropertyValue("icon2") throws the following error:
An exception of type 'System.Exception' occurred in Umbraco.Core.dll but was not handled in user code
Additional information: Exception while creating a value.
InnerException: "Object reference not set to an instance of an object."
Model.Content.GetPropertyValue<IPublishedContent>("icon2") throws the same error.
What am I doing wrong?
According to this answer, what you're doing is correct. However, I'm not sure why it's not working.
However, I have answered a similar question to this before, and I found a roundabout way of getting the node for a Udi:
You can get an IPublishedContent from your image string using this code:
// Your string.
var imageString = Model.Content.GetPropertyValue<string>("icon2");
// Get the guid from this string.
var imageGuidUdi = GuidUdi.Parse(imageString);
// Get the ID of the node!
var imageNodeId = ApplicationContext.Current.Services.EntityService.GetIdForKey(guidUdi.Guid, (UmbracoObjectTypes)Enum.Parse(typeof(UmbracoObjectTypes), guidUdi.EntityType, true));
// Finally, get the node.
var imageNode = Umbraco.TypedMedia(imageNodeId.Result);

Is Map attribute in DefaultLinkGenerator link() method thread safe?

We built an Grails (2.3.7) application where we are overriding the link(Map attr, String encoding = 'UTF-8') in DefaultLinkGenerator class. The reason we are doing this is to have the same URL throughout our application as it was business requirement from the customer. Basically in the overriding link() method, we are modifying the Map with new request parameters.
Now in Production we are seeing the following exception which occurs sporadically and we haven't been able to reproduce it locally.
2014-09-29 01:04:06,257 StackTrace ERROR Full Stack Trace:
java.lang.ArrayIndexOutOfBoundsException: 3
at org.codehaus.groovy.grails.web.mapping.UrlCreatorCache$ReverseMappingKey.<init>(UrlCreatorCache.java:196)
at org.codehaus.groovy.grails.web.mapping.UrlCreatorCache.createKey(UrlCreatorCache.java:62)
at org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingsHolder.getReverseMappingNoDefault(DefaultUrlMappingsHolder.java:265)
at org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingsHolder.getReverseMappingNoDefault(DefaultUrlMappingsHolder.java:257)
at org.codehaus.groovy.grails.web.mapping.DefaultLinkGenerator.link(DefaultLinkGenerator.groovy:213)
at gov.texas.multitenant.core.mapping.MultitenantLinkGenerator.super$2$link(MultitenantLinkGenerator.groovy)
The code in 'UrlCreatorCache$ReverseMappingKey' that throws the above ArrayIndexOutOfException can happen only when Map attribute (params) gets mutated during the loop. The excerpt of that code is below.
paramKeys = new String[params.size()];
paramValues = new String[params.size()];
int i = 0;
for (Map.Entry entry : params.entrySet()) {
**paramKeys[i] = String.valueOf(entry.getKey());** //throws exception here
String value = null;
if (entry.getValue() instanceof CharSequence) {
value = String.valueOf(entry.getValue());
}
...
paramValues[i] = value;
i++;
}
Now my question is, does this Map attribute THREAD SAFE? Can it get mutated between threads since we are modifying it?
Any feedback will be great appreciated. Thanks in advance.
You wouldn't know inside that method - anything implementing the Map interface is allowable. But that's not important - you're causing the problem (by being one of two concurrent editors of an apparently non-threadsafe instance) and can easily fix it.
Instead of modifying the map, create a new one (any Map implementation will do since only your code and the code in that method can access it) and modify that, and pass that in for link generation. Then throw it away and use the real map for further calculations. Something like
def attrs = ... // the 'real' map
def copy = [:] + attrs
copy.foo = 42
copy.bar = 'a very high one indeed'
String link = linkGenerator.link(copy)
//
...
def foo = attrs.foo // not available, set in copy, but no longer using that
...

Possible bug in getValidationMessages

I've created a custom entity level validation function, very similar to the one in the documentation (http://www.breezejs.com/documentation/validation). When I call getValidationErrors(), I get the following error:
Cannot read property 'name' of undefined
The error is coming from:
proto.getValidationErrors = function (property) {
assertParam(property, "property").isOptional().isEntityProperty().or().isString().check();
var result = __getOwnPropertyValues(this._validationErrors);
if (property) {
var propertyName = typeof (property) === 'string' ? property : property.name;
result = result.filter(function (ve) {
**return (ve.property.name === propertyName);**
});
}
return result;
};
There is no 'property' field in the custom entity level validator context. I'm using Breeze 1.4.5. Is this a bug? It seems to me the code above should check for 've.property', before trying to access the name.
Update
This has been fixed as of Breeze 1.4.7, available now.
Previous Post:
This is a bug that has already been fixed on GitHub and will be part of the next release (Breeze 1.4.7) out sometime next week. Or you can pull the breeze.xxx.js file from GitHub now if you need the fix earlier.

Grails data binding - Cannot make an immutable entity modifiable

On a Grails 2.1.0 I am trying to dynamically updating a field on a domain class. The object gets binded and it looks fine, until the save method is called, which throws the following exception:
java.lang.IllegalStateException: Cannot make an immutable entity modifiable.
try {
def bindParams = [:]
bindParams."$paramsFieldName" = "$paramsValue"
def domainClass = grailsApplication.domainClasses.find { it.clazz.simpleName == paramsDomain }.clazz
def objectInstance = domainClass.findById(paramsId)
objectInstance."$paramsFieldName" = "$paramsValue"
bindData(objectInstance, bindParams)
objectInstance.save(flush:true ,failOnError:false)
return objectInstance
}
catch (Exception ex) {
log.error ex
return null
}
I tried to bind the field using direct assigment and worked well.
objectInstance."$paramsFieldName" = convertToType( fieldType.name,paramsValue)
but then I need to handle the type conversion for each case (I assume). What I need is the BindDynamicMethod handles the binding for me. What happens to the object when binding it using the BindDynamicMethod that makes is immutable?. Or what am I doing wrong that is causing it?
=========================================================
PARTIALLY SOLVED
It turned out that this was happening on some of the domains, but some that were using cache on their mapping was throwing this exception.
class UploadSettings {
String profile = "default"
String displayName
String name
String value
String defaultValue
static mapping = {
//cache usage:'read-only'
}
}
So I guess now my question is if a domain is using cache , why cant we update its value? Or how can we do that? Is there a way to capture if the domain is immutable?
Thanks
Yes by setting it to read-only you are making the object immutable as the error says, IMHO this is misleading as we are in the context of caching but there is some rationale behind this.
If you need caching at the domain level then setting it to read-write should do the trick
See cache usages

Resources