work in progress

Architecture



AddDirectLink


  • Options
public class DirectLinkOptions
{
    public Type EntryType { get; set; }
    public string NotFoundPath { get; set; }
    public string NotAuthPath { get; set; }
    public string ErrorPath { get; set; }

    public string WarmupPath { get; set; }
    public string IndexTemplatePath { get; set; }
    public string AssetsPath { get; set; }
    public Action<string, ConcurrentDictionary<string, string>> AssetsParser { get; set; }

    public Func<Type, string> ComponentNameConverter { get; set; }
    public Func<string, string> FileNameConverter { get; set; }
    public string ScriptExtension { get; set; }
    public string StyleExtension { get; set; }

    public bool HotModuleReplacement { get; set; }

    public NodeServicesOptions NodeServicesOptions { get; set; }
    public int NodeInstanceCount { get; set; }
    public long NodeInstanceMemoryLimit { get; set; }
    public TimeSpan MemoryWatcherInterval { get; set; }
    public TimeSpan FileWatcherDelay { get; set; }
    public TimeSpan NodeServiceDisposingDelay { get; set; }

    public ILogger DirectLinkOutputLogger { get; set; }

    public int RequestsPerSecond { get; set; }
    public int QueuedRequestCount { get; set; }
    public int MaxLinkCount { get; set; }
}
  • Tags
public class TemplateTags
{
    public string Title { get; set; }
    public ICollection<string> Meta { get; }
    public IDictionary<string, string> MetaNames { get; }
    public IDictionary<string, string> MetaProperties { get; }
    public ICollection<string> Head { get; }
    public ICollection<string> Content { get; }
    public ICollection<string> Body { get; }
    public ICollection<string> GetMetaTags() { ... }
}

UseDirectLink



DirectLinkAttribute



DirectLinkMiddeware



DirectLink Controllers


DirectLink

DirectLink is base controller type and allows you:

  • invoke public .Net methods from React component
  • get initial state of component depending on ViewModel's constuctor called

DirectLinkRouter

Contains collection of routes.

public interface IDirectLinkRouter<out T> : IDirectLink<T> where T : RouterViewModel
{
    void MapRoutes(Action<ICollection<Route>> setupAction);
}

DirectLinkDispatcher

Cares about bidirectional communications:

  • keeps linked components props and connections
  • provides OnConnected/OnDisconnected events
  • allows setState and Invoke for linked components
public interface IDirectLinkDispatcher<out T> : IDirectLink<T> where T : ViewModel
{
    ConcurrentDictionary<string, object> Props { get; }
    ConcurrentDictionary<string, HashSet<string>> Connections { get; }

    Task OnConnectedAsync(string connectionId);
    Task OnDisconnectedAsync(string connectionId);

    Task SetStateAsync(string connectionId, string fullname, object state);
    Task SetStateAsync(string group, object state);
    Task SetStateAsync(object state);

    Task InvokeAsync(string connectionId, string fullname, string method, object[] args = null);
    Task InvokeAsync(string group, string method, object[] args = null);
    Task InvokeAsync(string method, object[] args = null);
}

DirectLinkController

DirectLinkController combines DirectLinkDispatcher and DirectLinkRouter features.


DirectLink ViewModels


  • ViewModel
public class ViewModel
{
    ICollection<ComponentDescriptor> Components { get; }

    public void AddComponents(Action<ICollection<ComponentDescriptor>> setupAction)
}
  • RouterViewModel
public class RouterViewModel : ViewModel
{
    public RouteComponent Component { get; set; }

    public virtual void OnRouted(Route route)
}

DirectLinkData


IDirectLinkData
public interface IDirectLinkData
{
    string App { get; }
    string Title { get; }
    IDictionary<string, object> States { get; }
    IDictionary<string, string> Scripts { get; }
    IDictionary<string, string> Styles { get; }
    IDictionary<string, IList<string>> Methods { get; }
    ICollection<string> Bidirectional { get; }
    string Message { get; }
    bool IsRouted { get; }
    bool IsAuthorized { get; }
}

DirectLinkData reflects current state of application.

If http request is being processed then DirectLinkMiddleware uses RoutingService to get DirectLinkData.

If user click on Link and requestData method is invoked then DirectLinkHub uses RoutingService to get DirectLinkData.


DirectLinkContext


DirectLinkContext
public class DirectLinkContext
{
    public HubCallerContext HubCallerContext { get; }
    public HttpContext HttpContext { get; }
    public ClaimsPrincipal User { get => this.HttpContext.User; }

    public string Title { get => this.Tags.Title; set => this.Tags.Title = value; }
    public TemplateTags Tags { get;  }
    public IDictionary<string, object> Data { get; }

    public string PathBase { get; }
    public string Path { get; }
    public string HubReferer { get; }

    public string GetLink<T>(params object[] args) { ... };
    public string GetLink(string name, params object[] args) { ... };
}

You can inject DirectLinkContext into ctor of ViewModels:

public class AppViewModel(DirectLinkContext context)

DirectLinkHub



Routes


The example of using routes is available on GitHub.


Services


ComponentTypesService

.NET Type <=> React Component

RoutingService

The following types can be used as parameters:

  • string
  • int
  • long
  • datetime
  • guid

There is a special type rest for capturing the remainder of the url.

AntiforgeryTokensService


AuthenticationService<TUser, TRole>


HotNodeServices


Component composititon



Hot Module Replacement


Use following options:

var isDevelopment = true;
services.AddDirectLink<App>(
    options => {
        ...
        if (isDevelopment) {
            options.HotModuleReplacement = true;
            options.NodeInstanceCount = 1;
            options.FileWatcherDelay = TimeSpan.FromMilliseconds(200);
        }
        ...
    },
    tags => tags.AddDefaultTemplateTags(..., nocache: isDevelopment, hmr: isDevelopment, isDevelopment: isDevelopment)
);

Tips