Real CustomAdaptor

Hello!
I want to exchange the default CustomAdaptor to a real custom data manager WITHOUT an impracticable static IEnumerable of the datasource as provided in your guidelines.
The thing is: 
We can´t register a CustomAdaptor Service because we are working with dynamic runtime keys.
So if a Component want´s to access our business logic and the underlying database it needs to provide a dynamic access token.
Well currently the only way to set a data manager instance is through the dependency injection:
<EjsDataManager @ref="@defaultDataManager" AdaptorInstance="@typeof(CustomAdaptor)" Adaptor="Adaptors.CustomAdaptor"></EjsDataManager>
Currently there is no way to set the dataManager instance manually e.g. in the OnAfterRenderAsync method.
Is there any other way to perform this?

8 Replies

RS Renjith Singh Rajendran Syncfusion Team February 14, 2020 12:31 PM UTC

Hi Nico, 

Thanks for contacting Syncfusion support. 

We cannot use/inject DataManager instance using dependency injection. From the point “Component want´s to access our business logic and the underlying database it needs to provide a dynamic access token” we understood that you want to use dynamic access token inside custom adaptor for DB access, if we understood your requirement correctly then we think using Custom Adaptor as component will suits for your case. 


Using custom adaptor as Blazor component has several advantages over using AdaptorInstance property. It supports dependency injection so that you can inject your access token generation logic inside the custom adaptor.  

If we have misunderstood kindly get back to us with more details regarding your requirement 

Regards, 
Renjith Singh Rajendran. 



BO boucher October 18, 2020 09:59 PM UTC

Can you give us a working full CRUD exemple project with a GRID and a CustomAdaptor exemple with DI ?


VN Vignesh Natarajan Syncfusion Team October 19, 2020 08:52 AM UTC

Hi Boucher,  
 
Thanks for your interest in Syncfusion products  
 
Query: “Can you give us a working full CRUD exemple project with a GRID and a CustomAdaptor exemple with DI ? 
 
As per your request we have prepared a CRUD sample with DataGrid and CustomAdaptor as a component. Please find the sample from below  
 
 
Note: To bind the data to Grid, kindly change the connectionstring of Northwnd.MDF file in App_Data filder in the OrderContext.cs file.   
 
Please get back to us if you have further queries.  
 
Regards, 
Vignesh Natarajan  
 



SL Stefan Limpert March 15, 2022 04:59 PM UTC

Hello Vignesh,

based on your example above i'm wondering is there a way to achieve a build a CustomAdaptorComponent with a parameter for a Service. Sort of <CustomAdaptor Service"@OrderService"></CustomAdaptor>? or maybe a kind of a generic CustomerAdaptor.

In my project business layer there are a lot of service classes that inherits from a generic service class. if i understand it right, i have now to build for all these service classes a separate adaptor component with lots of redundant code.

So what i need is one CustomAdaptor that operates with every of my services.

What is the best practice to do that?

Regards

Stefan



RN Rahul Narayanasamy Syncfusion Team March 17, 2022 02:26 PM UTC

Hi Stefan, 

Greetings from Syncfusion. 

Yes. We can define the CustomAdaptor component as Generic one and use that component inside various Grid / components. Refer the below code example.   

In below example, we have used two different grid with same custom adaptor component and passed TValue and DataSource as parameter to that custom component. Similar way you can define the Generic CustomAdaptor component.   

[Index.razor] 
<SfGrid TValue="Order" AllowPaging="true" EnableHover="false" AllowSorting="true"> 
    <GridPageSettings PageSize="5"></GridPageSettings> 
    <SfDataManager Adaptor="Adaptors.CustomAdaptor"> 
        <CustomComponent T="Order" Details="Orders"></CustomComponent> 
    </SfDataManager> 
    <GridColumns> 
….  
   </GridColumns> 
</SfGrid> 
 
[Test1.Razor] 
 
<SfGrid TValue="Employee" AllowPaging="true" EnableHover="false" AllowSorting="true">    <GridPageSettings PageSize="5"></GridPageSettings>    <SfDataManager Adaptor="Adaptors.CustomAdaptor">        <CustomComponent T="Employee" Details="Employees"></CustomComponent>    </SfDataManager>    <GridColumns>. . . . ..     </GridColumns></SfGrid>

[CustomComponent.Razor] 


 
@typeparam T @inherits DataAdaptor<T> <CascadingValue Value="@this">    @ChildContent</CascadingValue> @code {    [Parameter]    [JsonIgnore]    public RenderFragment ChildContent { getset; }     [Parameter]    public List<T> Details { getset; }     // Performs data Read operation    public override object Read(DataManagerRequest dm, string key = null)    {         IEnumerable<T> DataSource = (IEnumerable<T>)Details.Skip(dm.Skip).Take(dm.Take);. . . . . . . . .        return dm.RequiresCounts ? new DataResult() { Result = DataSource, Count = count } : (object)DataSource;    }}

Kindly download the sample from below  


Please get back to us if you have further queries. 

Regards, 
Rahul 



SL Stefan Limpert March 29, 2022 11:34 AM UTC

Hi Rahul,
thanks for your support. Based on your example i added a second parameter <U> to set my custom data service which worked fine, except one issue. My Blazor Server App uses ProtectedLocalStorage to store the user data like JWT Token etc. and in my DataService is receiving data from a WebAPI wich needs the JWT Token in requests.
Because of JSInterop there is no chance to get this informations before onAfterRender.
hen ReadAsync

[index.razor]

<SfGrid TValue="Order"AllowPaging="true" EnableHover="false" AllowSorting="true"> 

    <GridPageSettingsPageSize="5"></GridPageSettings> 
    <SfDataManager Adaptor="Adaptors.CustomAdaptor"> 
        <CustomComponent T="Order" Details="Orders" U="IOrdersDataService" ></CustomComponent> 
    </SfDataManager> 
    <GridColumns>

[CustomComponent.Razor] 

@typeparam T where T : class, IDataModel, new()

@typeparam U where U : IGenericService<T>

@inherits DataAdaptor<U>

<CascadingValue Value="@this"> @ChildContent</CascadingValue>


@code {

    [Parameter]

    [JsonIgnore]

    public RenderFragment ChildContent { get; set; }

    [Parameter]

    public List<T> Details { get; set; }

    // Performs data Read operation

    public override object Read(DataManagerRequest dm, string key = null)

    { ... }

    public override async Task<object> ReadAsync(DataManagerRequest dm, string key = null)

    {

        var data = await Service.GetListAsync();

        IEnumerable<T> DataSource = (IEnumerable<T>)data;

        if (dm.Search != null && dm.Search.Count > 0)

        { ....

[OrdersDataService]

...

public virtual async Task<IEnumerable<T>> GetListAsync()

{

   var bearer = (await _protectedLocalStorage.GetAsync<string>("BearerToken")).Value ?? string.Empty;

   ...set Authorization Header in HttpClient and fire request an so on

}

If i now open Index.razor the ReadAsync Method is firing the GetListAsync Method of th DataService and its running to an error as its try to get the values from ProtectedLocalStorage

[ERROR]

JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.

FYI: _Host render-mode = "Server"

I know the problem is probably at ProtectedLocalStorage, because the Reader tries to get data before Rendering but i don't think i'm the first with this approach. Either i have to delay the Reading method or i have to store the user data elsewhere. Do you have any suggestions?

Regards

Stefan




SL Stefan Limpert March 30, 2022 12:24 PM UTC

Hi

Its me again, after some researching and testing, i found a solution. Maybe i thought to much around the corner.

I' using now

[CustomComponent.Razor] 

@inherits DataAdaptor
[Parameter] public IGenericService<T> MyDataService { get; set; }

instead of

@typeparam U where U : IGenericService<T>
@inherits DataAdaptor<U>

and replaced all service calls in all overrided methods

 //var data = await Service.GetListAsync();
var data = await MyDataService.GetListAsync();

and voilá the cookie crumbles :-)

Regards

Stefan



RN Rahul Narayanasamy Syncfusion Team March 31, 2022 06:45 AM UTC

Hi Stefan,


Thanks for the update.


We are happy to hear that you have found the solution for your case. Please get back to us if you need further assistance.


Regards,

Rahul


Loader.
Up arrow icon