When I set the CanonicalKey or CanonicalUrl for a dynamic node, I get a NullReferenceException - asp.net-core-mvc

I'm using MVCSiteMapProvider v4.6.22 and have a dynamic node provider for one of my controllers.
Something like:
public class ProviderDetailsNodeProvider : DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
foreach (var provider in providers)
{
var dn = new DynamicNode()
{
Title = provider.Name,
ParentKey = "ParentKey",
Key = $"provider_master_{provider.ID}",
CanonicalUrl = "/url/something"
};
dn.RouteValues.Add("myRouteParamName", "myRouteParamValue");
yield return dn;
}
}
}
Without setting the CanonicalKey or CanonicalUrl properties of the DynamicNode, I get the correct behaviour. However I now wish to have multiple URLs pointing at the same content so I need to utilise the Canonical URL features of MVCSiteMapProvider.
If I attempt to set the CanonicalUrl as in the above snippet, or the CanonicalKey (my preferred choice), then when I attempt to use the helper methods, such as:
#Html.MvcSiteMap().SiteMapPath()
I get a NullReferenceException - it's the #Html.MvcSiteMap() which returns null.
What am I doing incorrectly, why do I get this NullReferenceException just by setting these properties against my dynamic nodes?
I'm using the MvcSiteMapProvider.MVC5 package, in an MVC6 application. I can't see a newer version on Nuget.

MVC 6 is not yet supported, as per the issue on NuGet.

Related

Microsoft.OData.Client $expand does not populate the model

I am using Microsoft.OData.Client based on the microsoft sample application.
Here's my simple WebAPI Controller:
[Route("test")]
[HttpGet]
public IHttpActionResult Test()
{
var context = _dynamicsContextFactory.CreateContext();
// adding this had no effect // context.MergeOption = MergeOption.AppendOnly;
// adding this had no effect // context.MergeOption = MergeOption.OverwriteChanges;
// adding this had no effect // context.MergeOption = MergeOption.NoTracking;
// adding this had no effect // context.MergeOption = MergeOption.PreserveChanges;
var result = context.SalesOrderHeadersV2.Expand("SalesOrderLines").Take(1).ToList();
return Ok(result);
}
The client generates the correct URL.
https://example.com/data/SalesOrderHeadersV2?$top=1&$expand=SalesOrderLines
I can see in fiddler the SalesOrderLines property returned in the JSON.
However when I inspect the result variable (or view the output) there is no SalesOrderLines property. So the order lines have not been mapped into my result object from the data downloaded from the oData source.
Important Note: I am using EDMXTrimmer to reduce the number of entities in my client, could this be an issue If I’m missing a joining entity? (It seems unlikely there's a joining entity in this case)
Clue?
When I try to change this line:
var result = context.SalesOrderHeadersV2.Expand(x=>x.SalesOrderLines).Take(1).ToList();
It will not compile because 'SalesOrderHeaderV2' does not contain a definition for 'SalesOrderLines' ...
Note: context.SalesOrderLines does exist.
The issue was that EDMXTrimmer removed the navigation properties.
EDMXTrimmer has since been fixed.

using signalR .net core client

I have set up a signalR website .net core. My function in my hub is:
public async Task Notify(int id) {
await Clients.All.InvokeAsync("Notified", id);
}
I have also tested this with the following js:
let connection = new signalR.HubConnection(myURL);
connection.on('Notified', data => {
console.log(4, data);
});
connection.start();
The js code seems to work fine and I see the log when I try connection.Invoke('Notify').
Now I have a console app that can needs to make the invoke. I am trying this in two ways and don't mind either solution:
1. A mvc controller within the signalR website that can take the id and invoke 'Notified'.
2. Use the client library Microsoft.AspNetCore.SignalR.Client in the console app.
The way 1 I have only done in classic asp.net like this:
GlobalHost.ConnectionManager.GetHubContext(hubName)
But couldn't find a way to do this in .net core.
Way 2 I have used the library and tried this so far:
var con = new HubConnectionBuilder();
con.WithUrl(myURL);
var connection = con.Build();
connection.InvokeAsync("Notify",args[0]).Wait();
This is the closest I have come to create a connection in the same way as the js code. However this code throws a null pointer when calling connection.InvokeAsync. The connection object is not null. It seems to be an internal object that is null. According to the stack trace the exception is thrown when a MoveNext() function is internally called.
Well looks like both are not currently possible. As of now I just used a forced way which is hopefully temporary.
I have created and used the following base class for hubs:
public abstract class MyHub : Hub
{
private static Dictionary<string, IHubClients> _clients = new Dictionary<string, IHubClients>();
public override Task OnConnectedAsync()
{
var c = base.OnConnectedAsync();
_clients.Remove(Name);
_clients.Add(Name, Clients);
return c;
}
public static IHubClients GetClients(string Name) {
return _clients.GetValueOrDefault(Name);
}
}
GlobalHost is gone. You need to inject IHubContext<THub> like in this sample.
This can be a bug in SignalR alpha1. Can you file an issue on https://github.com/aspnet/signalr and include a simplified repro?

RazorEngine WebApiTemplateBase #Url.Content()

How can I get #Url.Content() working in my _Layout.cshtml when RazorEngine is being used from ASP.NET Web API?
RazorEngine (v.3.7.2) only deals with the Razor syntax and not the additional helper methods like #Html or #Url. These can be added by extending the TemplateBase<> and setting it in the configuration.
There are code examples in some old issues: #26, #29; in an unreleased, incomplete piece of code in MvcTemplateBase.cs; and in the documentation for Extending the Template Syntax.
My problem is I'm using ASP.NET Web API (v.1) which won't have HttpContext.Current (nor should it). I want to provide a UrlHelper as I want to use its Content() method but it needs to be instantiated with the HttpRequestMessage which won't be available.
Perhaps there's no way to get #Url helper methods for my compiled layout. Perhaps I need some other way of getting the absolute path from the virtual path. It seems I'd still need some way of checking the Request though.
A way to get this working is to follow the direction set by Extending the Template Syntax and use VirtualPathUtility.ToAbsolute() in a helper method.
using System.Web;
using RazorEngine.Templating;
namespace MyNamespace.Web
{
public abstract class WebApiTemplateBase<T> : TemplateBase<T>
{
protected WebApiTemplateBase()
{
Url = new UrlHelper();
}
public UrlHelper Url;
}
public class UrlHelper
{
public string Content(string content)
{
return VirtualPathUtility.ToAbsolute(content);
}
}
}
Set up the TemplateService configuration with this extension of the TemplateBase<>.
var config =
new RazorEngine.Configuration.TemplateServiceConfiguration
{
TemplateManager = new TemplateManager(),
BaseTemplateType = typeof(WebApiTemplateBase<>)
};

Fetch windows setting value

How do I fetch the Measurement System setting value in javascript?
I'm guessing that it would be throw some WinJS call.
The logical place would be Windows.Globalization, but not seeing if offered there. One pretty simple workaround - faster to write than to research the setting :) is to create a Windows Runtime Component in C# that calls in to System.Globalization:
namespace WindowsRuntimeComponent
{
public sealed class RegionalSettings
{
public bool isMetric()
{
return System.Globalization.RegionInfo.CurrentRegion.IsMetric;
}
}
}
Then add as a reference to your JavaScript app and invoke there:
var r = new WindowsRuntimeComponent.RegionalSettings;
var isMetric = r.isMetric();

use camel case serialization only for specific actions

I've used WebAPI for a while, and generally set it to use camel case json serialization, which is now rather common and well documented everywhere.
Recently however, working on a much larger project, I came across a more specific requirement: we need to use camel case json serialization, but because of backward compatibility issues with our client scripts, I only want it to happen for specific actions, to avoid breaking other parts of the (extremely large) website.
I figure one option is to have a custom content type, but that then requires client code to specify it.
Is there any other option?
Thanks!
Try this:
public class CamelCasingFilterAttribute : ActionFilterAttribute
{
private JsonMediaTypeFormatter _camelCasingFormatter = new JsonMediaTypeFormatter();
public CamelCasingFilterAttribute()
{
_camelCasingFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
ObjectContent content = actionExecutedContext.Response.Content as ObjectContent;
if (content != null)
{
if (content.Formatter is JsonMediaTypeFormatter)
{
actionExecutedContext.Response.Content = new ObjectContent(content.ObjectType, content.Value, _camelCasingFormatter);
}
}
}
}
Apply this [CamelCasingFilter] attribute to any action you want to camel-case. It will take any JSON response you were about to send back and convert it to use camel casing for the property names instead.

Resources