Moe Sisko
Moe Sisko

Reputation: 12063

Formatting nullable decimal in RazorEngine

RazorEngine.dll version is 3.2.

Example code inside a razor engine template (cshtml file) :

      @foreach(var row in Model.Trades)
      {            
          <tr>          
             <td>
                @string.Format("{0:N2}",row.Amount)
             </td>
          </tr>
      }     

where row.Amount is defined in the Trades class as : public decimal? Amount;

The stack trace fromRazorEngine is :

> System.ArgumentNullException was caught   HResult=-2147467261  
> Message=Value cannot be null. Parameter name: args   Source=mscorlib  
> ParamName=args   StackTrace:
>        at System.String.Format(String format, Object[] args)
>        at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite
> site, T0 arg0, T1 arg1, T2 arg2)
>        at CompiledRazorTemplates.Dynamic.ccdceaafafffaefee.Execute()
>        at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext
> context) in
> c:\Users\Matthew\Documents\GitHub\RazorEngine\src\Core\RazorEngine.Core\Templating\TemplateBase.cs:line
> 126
>        at RazorEngine.Templating.TemplateService.Run(ITemplate template, DynamicViewBag viewBag) in
> c:\Users\Matthew\Documents\GitHub\RazorEngine\src\Core\RazorEngine.Core\Templating\TemplateService.cs:line
> 608
>        at RazorEngine.Templating.TemplateService.Parse(String razorTemplate, Object model, DynamicViewBag viewBag, String cacheName)
> in
> c:\Users\Matthew\Documents\GitHub\RazorEngine\src\Core\RazorEngine.Core\Templating\TemplateService.cs:line
> 439
>        at RazorEngine.Razor.Parse[T](String razorTemplate, T model, String cacheName) in
> c:\Users\Matthew\Documents\GitHub\RazorEngine\src\Core\RazorEngine.Core\Razor.cs:line
> 276

The error occurs when Amount is null. This is a workaround which seems to work ok :

@foreach(var row in Model.Trades)
{            
   <tr>          
      <td>
         @if (row.Amount != null)
         {                
           <text>@string.Format("{0:N4}", row.Amount)</text>
         }
     </td>
  </tr>
}

Any ideas, or at least a better workaround ? Thanks.

EDIT :

The workaround below is a bit more compact :

         <td>
            @(row.Amount == null ? "" : row.Amount.ToString("N4"))
         </td>

Does anyone know if Razor in MVC behaves in the same way ? Or is this behaviour specific to RazorEngine.dll ?

Upvotes: 0

Views: 957

Answers (1)

Stephen Reindl
Stephen Reindl

Reputation: 5829

The error above is from String.Format(). Interesting, as the documentation on String.Format() explains that null arguments should result in empty string.

For whatever reason Razor selects the overload String.Format(format, Object[]) to format your string. As your value is null.

I've created a small example at to explain the problem:

int? val = null;

// this one fails:
string template = "Hello @string.Format(\"{0:N4}\", Model.Value)! Welcome to Razor!";
string result = Razor.Parse(template, new { Value = val });

// this (ugly) workaround works:
string template = "Hello @(string.Format(\"{0:N4}{1}\", Model.Value, string.Empty))! Welcome to Razor!";
string result = Razor.Parse(template, new { Value = val });

// this (not so ugly) workaround works as well:
string template = "Hello @(string.Format(\"{0:N4}\", (Object)Model.Value))! Welcome to Razor!";
string result = Razor.Parse(template, new { Value = val });

Your workaround will work as well.

If this is a bug or a feature in Razor, I do not know...

EDIT (2): Added the smarter workaround from Moe Sisko

EDIT: Rewrote to really answer the question ...

Upvotes: 2

Related Questions