Home > Enterprise >  Dependency Injection issues with Blazor
Dependency Injection issues with Blazor

Time:09-27

I am using .NET 5 and Blazor and also I am using DevExpress to create Pie Chart.

The problem I have is, that inside of the main page, I have a few blazor components, and every component has a DevExpress pie chart.

What I need is to inject a class inside of every component, and I need to every component to manage his own instance of this object, but it looks like I have one object per URL, how can I solve this?

This is the code of one of the components with one DevExpress donut chart:

@using System.Drawing;
@inject IColorPaletteService _colorPaletteService

<hr class="border-gold" />
<h4 class="text-center text-active">Overall</h4>


<DxChart Data="@_genderList" CustomizeSeriesPoint="@PreparePointColor"
         CssClass="w-100">
    <DxChartLegend Visible="false" />

    <DxChartDonutSeries ValueField="@((DashboardValues i) => i.Value)"
                        ArgumentField="@(i => i.Detail)"
                        SummaryMethod="Enumerable.Sum">
    </DxChartDonutSeries>
</DxChart>

<div style="position: relative; top: -26%; left: 90%; transform: translate(-50%, -50%);">
    <h1 class="text-secondary">@Completed%</h1>
</div>


@code {
    private IEnumerable<DashboardValues> _genderList;
    private int Completed { get; set; }
    
    protected override void OnInitialized()
    {
        base.OnInitialized();

        _genderList = new List<DashboardValues>
        {
            new DashboardValues {Id = 1, Detail = "Completed", Value = 90},
            new DashboardValues {Id = 1, Detail = "Remaining", Value = 10},
        };

        Completed = _genderList.First(x => x.Detail == "Completed").Value;
    }

    protected void PreparePointColor(ChartSeriesPointCustomizationSettings pointSettings)
    {
        pointSettings.PointAppearance.Color = _colorPaletteService.GetNextColor;
    }
}

This is the object I am trying to inject:

@inject IColorPaletteService _colorPaletteService

And this is the code of the class I am trying to inject:

using System.Collections.Generic;
using System.Drawing;

namespace WebClient.Services.Dashboard
{
    public class ColorPaletteService: IColorPaletteService
    {
        private List<Color> ColorList { get; set; }
        private int CurrentColorIndex { get; set; }
        private int ListLenght { get; set; }

        public ColorPaletteService()
        {
            CurrentColorIndex = 0;

            ColorList = new List<Color>
            {
                ColorTranslator.FromHtml("#00546C"),
                ColorTranslator.FromHtml("#518197"),
                ColorTranslator.FromHtml("#96898A"),
                ColorTranslator.FromHtml("#C0AFA5"),
                ColorTranslator.FromHtml("#D2C7C3"),
                ColorTranslator.FromHtml("#EDE6E0"),
                ColorTranslator.FromHtml("#BA9764"),
                ColorTranslator.FromHtml("#808080"),
                ColorTranslator.FromHtml("#D0D0D0")
            };

            ListLenght = ColorList.Count;
        }

        public Color GetNextColor
        {
            get
            {
                if (CurrentColorIndex < ListLenght)
                {
                    Color currentColor = ColorList[CurrentColorIndex];

                    // Increase the index for the next iteration
                    CurrentColorIndex  = 1;
                    return currentColor;
                }

                CurrentColorIndex = 0;
                return ColorList[0];
            }
        }
    }
}

The problem I have is that having scoped injected this object, but the scope is not every component but looks like is one object by URL, this cause that the function "GetNextColor" of the class "ColorPaletteService" pass a kind of random colors instead of following the order of the variable "ColorList".

Any help please?

CodePudding user response:

You are trying to maintain a component-specific state inside an injected service instance. Instead, you should maintain the state inside the component. Your code can then look like this:

PieChart.razor

@code
{
   int currentColorIndex = 0;
   protected void PreparePointColor(ChartSeriesPointCustomizationSettings pointSettings)
    {
        currentColorIndex = colorPaletteService.GetNextColor(currentColorIndex, out var color);
        pointSettings.PointAppearance.Color = color;
    }
}

And palette service as:

public int GetNextColor(int CurrentColorIndex, out Color col)
{
      col = CurrentColorIndex < ListLenght ? ColorList[CurrentColorIndex] : ColorList[0];
      return CurrentColorIndex >= ListLenght ? 0 : CurrentColorIndex 1;    
}

And set the palette service as a singleton. Note that the transients in the blazor server are poorly defined. Server WebSocket keeps the session alive as long as it is not disconnected. So the transients here behave differently than in the traditional .net controller.

CodePudding user response:

The class should be added as Transient:

services.AddTansient<IColorPaletteService, ColorPaletteService>();

this will give each component its own instance.

  • Related