SkillAgentSearch skills...

Directlink

Library for building single-page web applications

Install / Use

/learn @directlinkcore/Directlink
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

DirectLink

Library for building single-page web applications that makes the world easier for ASP.NET Core developers who use React.

Features

  • Server-side rendering
  • Real-time communications:
    • invoke .NET methods from React components
    • set state of components from .NET world
  • Flexible server-side routing

Installation

Create ASP.NET Core project and add package:

dotnet new web -o Sample && cd Sample
dotnet remove package Microsoft.AspNetCore.App
dotnet add package Microsoft.AspNetCore.App -v 2.1.5
dotnet add package DirectLink.Core.React

Initialize npm and install packages:

npm init -y
npm install directlink-react
npm install -D @babel/core babel-loader webpack webpack-cli
npm install -D @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties
<details> <summary><code>package.json</code></summary>
{
    "name": "sample",
    "version": "1.0.0",
    "description": "",
    "scripts": {
        "build": "webpack"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
        "directlink-react": "1.0.5"
    },
    "devDependencies": {
        "@babel/core": "7.1.2",
        "@babel/plugin-proposal-class-properties": "7.1.0",
        "@babel/preset-env": "7.1.0",
        "@babel/preset-react": "7.0.0",
        "babel-loader": "8.0.4",
        "webpack": "4.23.1",
        "webpack-cli": "3.1.2"
    }
}
</details> <details> <summary>add <code>webpack.config.js</code></summary>
let path = require('path');

module.exports = {
    mode: 'development',
    entry: { app: 'app.jsx' },
    output: {
        path: path.join(__dirname, 'wwwroot/dist'),
        filename: '[name].js'
    },
    resolve: {
        modules: ['clientApp', 'node_modules']
    },
    externals: {
        'react': 'React',
        'react-dom': 'ReactDOM'
    },
    module: {
        rules: [{
            test: /\.jsx?$/,
            exclude: /node_modules/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-env', '@babel/preset-react'],
                    plugins: ['@babel/plugin-proposal-class-properties']
                }
            }
        }]
    }
};
</details> <br>

Add service and configure pipeline in Startup.cs:

services.AddDirectLink<App>(tags => tags.AddDefaultTemplateTags(title: "Sample"));
app.UseDirectLink(components => components.Map<App>(script: "/dist/app.js"));
<details> <summary><code>Startup.cs</code></summary>
using DirectLinkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace Sample
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDirectLink<App>(tags => tags.AddDefaultTemplateTags(title: "Sample"));
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            }

            app.UseDirectLink(components => components.Map<App>(script: "/dist/app.js"));
        }
    }
}
</details>

Usage

Add app.jsx to clientApp folder:

components.App = class App extends React.Component {
    constructor(props) {
        super(props);
        directlink.init(this);
    }

    componentWillUnmount() {
        directlink.dispose(this);
    }

    sendMessage = () => {
        this.AddMessage(this.state.message) //here we invoke App.AddMessage method
            .then(() => this.setState({ message: '' }));
    }

    onChange = (event) => {
        this.setState({ [event.target.name]: event.target.value });
    }

    onKeyPress = (event) => {
        if (event.key === 'Enter') {
            this.sendMessage();
        }
    }

    render() {
        return (
            <div className="jumbotron">
                <div className="row mb-3">
                    <div className="col-12 col-sm-8 col-md-9 col-lg-10 mb-3 mb-sm-0">
                        <input type="text" className="form-control" name="message"
                            placeholder="message" autoComplete="off"
                            value={this.state.message} onChange={this.onChange} onKeyPress={this.onKeyPress} />
                    </div>
                    <div className="col-12 col-sm-4 col-md-3 col-lg-2">
                        <button type="button" className="btn btn-primary w-100"
                            onClick={this.sendMessage}>Send</button>
                    </div>
                </div>
                <ul className="list-unstyled">
                    {this.state.Messages.slice().reverse().map(message =>
                        <li key={message.Id}>
                            <div className='alert alert-primary'>{message.Text}</div>
                        </li>)}
                </ul>
            </div>
        );
    }
};

Add Message.cs:

using System;

namespace Sample
{
    public class Message
    {
        public Guid Id { get; }

        public string Text { get; }

        public Message(string text) => (Id, Text) = (Guid.NewGuid(), text);
    }
}

Add App.cs:

using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using DirectLinkCore;

namespace Sample
{
    public class App : DirectLinkDispatcher<AppViewModel>
    {
        private static ConcurrentQueue<Message> _messages = new ConcurrentQueue<Message>();

        public IReadOnlyCollection<Message> GetMessages() => _messages;

        public async Task AddMessage(string text)
        {
            _messages.Enqueue(new Message(text));
            await SetStateAsync(new { Messages = _messages }); //here we setState of App component
        }
    }
}

Add AppViewModel.cs:

using System.Collections.Generic;
using DirectLinkCore;

namespace Sample
{
    public class AppViewModel : ViewModel
    {
        public IReadOnlyCollection<Message> Messages { get; }

        public AppViewModel(App app) => Messages = app.GetMessages();
    }
}

Build client and run project:

npm run build
dotnet run

Open http://localhost:5000 in several tabs and check that all clients can text each other.

Documentation

See live samples and documentation for more details.

License

Apache 2.0

Related Skills

View on GitHub
GitHub Stars6
CategoryDevelopment
Updated2y ago
Forks0

Languages

C#

Security Score

55/100

Audited on Sep 24, 2023

No findings