GitOpsDevHub

MIT License

Stars
0

steps

Service Technical Enhancement Proposals


License

This repository is licensed under the MIT License. See the LICENSE file for more information.

Getting Started

Using the Codespace Environment

To use the Codespace environment for this project, follow these steps:

  1. Open Codespace:

    • Navigate to the repository on GitHub.
    • Click on the "Code" button and select "Open with Codespaces".
    • If you don't have a Codespace created, click on "New Codespace".
  2. Wait for Setup:

    • The Codespace will automatically set up the development environment based on the configurations in the repository.
    • This includes installing all necessary dependencies and extensions for React/TypeScript and C# development.
  3. Start Coding:

    • Once the setup is complete, you can start coding immediately.
    • The environment is pre-configured with all the tools and extensions you need for development, linting, formatting, and debugging.
  4. Run and Debug:

    • Use the integrated terminal and debugger in VSCode to run and debug your code.
    • The environment includes tasks for building and debugging both TypeScript and C# projects.
  5. CI/CD Integration:

    • The Codespace is integrated with the existing CI/CD pipelines.
    • You can run tests and deploy directly from the Codespace environment.

Setting Up the Backend (SignalR + CosmosDB)

You’ll need an ASP.NET Core backend with SignalR that communicates with CosmosDB.

Step 1: Create ASP.NET Core SignalR Project

dotnet new webapi -n SignalRCosmosDemo
cd SignalRCosmosDemo

Step 2: Install Required NuGet Packages

dotnet add package Microsoft.Azure.Cosmos
dotnet add package Microsoft.AspNetCore.SignalR

Step 3: Create a SignalR Hub

In your Hubs folder, create a RecordHub.cs file:

using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;

public class RecordHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

Step 4: Set Up CosmosDB Service

Create a CosmosService.cs that will handle getting/setting records in CosmosDB.

using Microsoft.Azure.Cosmos;
using System.Threading.Tasks;

public class CosmosService
{
    private readonly Container _container;

    public CosmosService(CosmosClient cosmosClient, string databaseName, string containerName)
    {
        _container = cosmosClient.GetContainer(databaseName, containerName);
    }

    public async Task<T> GetRecordAsync<T>(string id, string partitionKey)
    {
        try
        {
            ItemResponse<T> response = await _container.ReadItemAsync<T>(id, new PartitionKey(partitionKey));
            return response.Resource;
        }
        catch (CosmosException)
        {
            return default;
        }
    }

    public async Task SetRecordAsync<T>(T record, string id, string partitionKey)
    {
        await _container.UpsertItemAsync(record, new PartitionKey(partitionKey));
    }
}

Step 5: Add SignalR, CosmosDB, and DI in Startup.cs

Configure services and SignalR:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    // CosmosDB configuration
    services.AddSingleton<CosmosClient>(sp =>
        new CosmosClient(Configuration["CosmosDB:ConnectionString"]));
    
    services.AddSingleton<CosmosService>(sp =>
        new CosmosService(
            sp.GetRequiredService<CosmosClient>(),
            Configuration["CosmosDB:DatabaseName"],
            Configuration["CosmosDB:ContainerName"]));

    // Add SignalR
    services.AddSignalR();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapHub<RecordHub>("/recordHub");
    });
}

Step 6: Add an API Controller to Interact with CosmosDB

Create a RecordController.cs file to handle CosmosDB interactions.

using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

[ApiController]
[Route("api/[controller]")]
public class RecordController : ControllerBase
{
    private readonly CosmosService _cosmosService;
    private readonly IHubContext<RecordHub> _hubContext;

    public RecordController(CosmosService cosmosService, IHubContext<RecordHub> hubContext)
    {
        _cosmosService = cosmosService;
        _hubContext = hubContext;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> Get(string id, [FromQuery] string partitionKey)
    {
        var record = await _cosmosService.GetRecordAsync<dynamic>(id, partitionKey);
        if (record == null) return NotFound();
        return Ok(record);
    }

    [HttpPost]
    public async Task<IActionResult> Set([FromBody] dynamic record, [FromQuery] string id, [FromQuery] string partitionKey)
    {
        await _cosmosService.SetRecordAsync(record, id, partitionKey);
        await _hubContext.Clients.All.SendAsync("ReceiveMessage", "server", $"Record {id} updated");
        return Ok();
    }
}

Step 7: Configure appsettings.json for CosmosDB

{
  "CosmosDB": {
    "ConnectionString": "<Your CosmosDB Connection String>",
    "DatabaseName": "YourDatabase",
    "ContainerName": "YourContainer"
  }
}

Setting Up the Frontend (React with SignalR)

Step 1: Create a React App

npx create-react-app signalr-cosmos-frontend
cd signalr-cosmos-frontend

Step 2: Install Required Packages

npm install @microsoft/signalr axios

Step 3: Create a .env file

Create a .env file in the root of your React project and add the following environment variables:

REACT_APP_API_BASE_URL=http://localhost:5000
REACT_APP_SIGNALR_HUB_URL=${REACT_APP_API_BASE_URL}/recordHub

Step 4: Create SignalR Connection in App.js

import React, { useEffect, useState } from 'react';
import * as signalR from '@microsoft/signalr';
import axios from 'axios';

function App() {
  const [messages, setMessages] = useState([]);
  const [record, setRecord] = useState(null);
  const [newRecord, setNewRecord] = useState('');

  const API_BASE_URL = process.env.REACT_APP_API_BASE_URL || 'http://localhost:5000';
  const SIGNALR_HUB_URL = process.env.REACT_APP_SIGNALR_HUB_URL || `${API_BASE_URL}/recordHub`;

  useEffect(() => {
    // Create SignalR connection
    const connection = new signalR.HubConnectionBuilder()
      .withUrl(SIGNALR_HUB_URL)
      .withAutomaticReconnect()
      .build();

    connection.start()
      .then(() => console.log('Connected to SignalR'))
      .catch(err => console.log('Error connecting to SignalR: ', err));

    // Receive messages from SignalR hub
    connection.on('ReceiveMessage', (user, message) => {
      setMessages(prevMessages => [...prevMessages, `${user}: ${message}`]);
    });

    return () => {
      connection.stop();
    };
  }, [SIGNALR_HUB_URL]);

  const getRecord = async () => {
    const response = await axios.get(`${API_BASE_URL}/api/record/1`, {
      params: { partitionKey: 'default' }
    });
    setRecord(response.data);
  };

  const setNewRecordToDb = async () => {
    await axios.post(`${API_BASE_URL}/api/record`, { data: newRecord }, {
      params: { id: '1', partitionKey: 'default' }
    });
    setNewRecord('');
  };

  return (
    <div className="App">
      <h1>SignalR and CosmosDB Demo</h1>

      <div>
        <h2>Record</h2>
        <button onClick={getRecord}>Get Record</button>
        <pre>{JSON.stringify(record, null, 2)}</pre>
      </div>

      <div>
        <h2>Update Record</h2>
        <input value={newRecord} onChange={e => setNewRecord(e.target.value)} />
        <button onClick={setNewRecordToDb}>Update</button>
      </div>

      <div>
        <h2>Messages</h2>
        {messages.map((msg, idx) => <p key={idx}>{msg}</p>)}
      </div>
    </div>
  );
}

export default App;

Run the POC

  • Backend: Run the ASP.NET Core SignalR server and API:

    dotnet run
    
  • Frontend: Start the React frontend:

    npm start
    
  • Fix Issues: Address any issues by running:

    npm audit fix --force
    

How This Works:

  1. The React app connects to the SignalR Hub (RecordHub) when the page loads.
  2. Users can trigger CosmosDB get/set operations via the API endpoints (/api/record).
  3. When the record is updated, the backend pushes a message to all connected SignalR clients, notifying them that the record was updated.
  4. The React frontend receives real-time updates and displays them without polling.

This POC demonstrates the basic structure of integrating SignalR for real-time communication, with CosmosDB for storage operations. Let me know if you'd like further details or customization for your scenario!

Prerequisites

There are no prerequisites required to run this code or use this repository.

To set up the Codespace environment, ensure you have the following tools installed:

  • Git: Version control system to clone the repository.
  • GitHub CLI: To manage Codespaces from the command line (optional).
  • Docker: Required for running the development container.
  • Visual Studio Code: Recommended for the best development experience.

Installing

This repository does not hold installable content.

To set up the Codespace environment, follow these steps:

  1. Clone the Repository:

    git clone https://github.com/dciborow/GitOpsDevHub.git
    cd GitOpsDevHub
    
  2. Open in Codespace:

    • Open the repository in a Codespace as described in the "Getting Started" section.
  3. Wait for Setup:

    • The Codespace will automatically set up the development environment based on the configurations in the repository.
  4. Start Coding:

    • Once the setup is complete, you can start coding immediately.

Deployment (CI/CD)

At this time, the repository does not use continuous integration or produce a website, artifact, or anything deployed.

The Codespace environment is integrated with the existing CI/CD pipelines. You can run tests and deploy directly from the Codespace environment.


Access

Contributing

This repository prefers outside contributors start forks rather than branches. For pull requests more complicated than typos, it is often best to submit an issue first. If you are a new potential collaborator who finds reaching out or contributing to another project awkward, you may find it useful to read these tips & tricks on InnerSource Communication.

Support & Reuse Expectations

The creators of this repository DO NOT EXPECT REUSE. If you do use it, please let us know via an email or leave a note in an issue, so we can best understand the value of this repository.


How to Accomplish Common User Actions