Connect a WinForms Data Grid to an Arbitrary ASP.NET Core WebAPI Service Powered by EF Core (2024)

In the post Modern Desktop Apps And Their Complex Architectures I summarized a while ago how the world of application architecture has evolved in the last years. Our WinForms team published a follow-up with WinForms — Connect a .NET Desktop Client to Secure Backend Web API Service (EF Core with OData). In this post I will take another step back and demonstrate how to use an even simpler service setup together with the DevExpress WinForms Data Grid.

Basic assumptions

Many application systems which originated as desktop apps have been extended over time with data access services that work independently of any original client-side direct binding patterns. For instance, web applications or mobile frontends may have entered the picture at some point, and this necessitated a broader look at the data access architecture. On the other hand, perhaps your application system has not gone through such steps yet!

The idea is, in either case, to shift the direct connection to a database server, e.g. using port 1433 for a Microsoft SQL Server, to a place where it’s not the responsibility of the desktop app anymore. This may be a requirement for maintenance reasons, once your system has more than one client, or it may be done to facilitate a cleaner architecture.

For purposes of this demo, the data service will be quite simple. We assume that it uses Entity Framework Core for data access, but the point is only that data access should not be difficult on the level of the service. Equally we assume that it’s easy to add features to the service as needed — of course that’s not always true, but in this post we will not yet focus on the complicated scenarios where the service cannot be touched.

The final assumption we make is that the service is more “general purpose” than the one described in the OData-related post linked above. This is not meant to say that using OData is a bad idea, but for this demo we’ll do without it.

The demo repository

You can find the sample code for this demo in the GitHub repository. The Readme file describes how to run the sample. Please contact us if you have any questions or comments!

If you are interested in a few technical points about the sample code, please read on for a description of the sample structure and some of the relevant code files.

The Backend: an ASP.NET Core WebAPI service using Entity Framework Core

The backend project is called DataService and it was created using the standard ASP.NET Core WebAPI template. It uses top-level statements and the “minimal API” configuration format for the service, it does not include anything that’s not necessary for this demo — all so you can focus on the code required for the demo setup itself. There are two endpoint handlers in the service, one to generate some test data and the other to query data.

This second handler, at the URL /data/OrderItems, is the important one for this post. For the sample implementation, the handler accepts several optional parameters to support the skip, take and sort features. The code is simple, it queries data from the Entity Framework Core database context, and uses the standard IQueryable<T> based helpers to implement the data shaping functionality. The TotalCount field is returned together with the data since we need this on the client side to determine how much data is available to query.

app.MapGet("/data/OrderItems", async ( DataServiceDbContext dbContext, int skip = 0, int take = 20, string sortField = "Id", bool sortAscending = true) =>{ var source = dbContext.OrderItems.AsQueryable() .OrderBy(sortField + (sortAscending ? " ascending" : " descending")); var items = await source.Skip(skip).Take(take).ToListAsync(); var totalCount = await dbContext.OrderItems.CountAsync(); return Results.Ok(new { Items = items, TotalCount = totalCount });});

To be a bit more abstract about it: this endpoint handler exemplifies the service functions that you’ll need in a data service, in order to provide required information to a frontend application, or a specialized component like the Data Grid. The implementation and the set of supported data shaping features will vary, but logically any data access will require some endpoints which work along these lines.

The Frontend: a Windows Forms app with a DevExpress Data Grid

In the project WinForms.Client you’ll find the class OrderItem. This is the type the client works with, representing the data on the backend. However, note that this type is not the same as the one the backend uses! If you compare it carefully to the OrderItem in the DataService, you’ll find that the frontend type does not exhibit the same Entity Framework Core artifacts as the backend type. Specifically the virtual keyword is absent from the property declarations in the frontend type.

In a real application these types may (and probably would!) differ more. The sample setup is simple and the data types were introduced for demonstration purposes only, but in reality the discrepancies between a backend persistent type and a frontend model of service-retrieved data will likely be much more obvious.

In the MainForm of the Windows Forms application, the GridControl component is configured with columns corresponding to the properties of the OrderItem. The component is bound to a VirtualServerModeSource instance on the form, whose RowType property was set to OrderItem. This allows the grid to discover the columns from the data source automatically.

Connect a WinForms Data Grid to an Arbitrary ASP.NET Core WebAPI Service Powered by EF Core (1)

To fetch the data, the VirtualServerModeSource uses at least two event handlers (though one of them is optional depending on circ*mstances). Code for the handlers of the ConfigurationChanged and MoreRows events can be found in MainForm.cs.

The ConfigurationChanged handler is executed when the grid changes some relevant part of its runtime configuration as a reaction to user interaction, e.g. when the user clicks a column header to apply sorting. The MoreRows handler comes in when an initial fetch operation returns a result which indicates that more data is available. In this case, the grid attempts to retrieve more rows if and when the user scrolls to the bottom of the currently loaded set of data.

In future posts we will go into some more depth about the VirtualServerModeSource, but of course there is also complete documentation for this component if you want to know more.

In the sample, loading logic for the virtual data source is encapsulated in the class VirtualServerModeDataLoader, which is instantiated by the ConfigurationChanged event handler, i.e. on each change of the grid’s runtime configuration by the end user. The loader class receives the current configuration on instantiation, and the code shows, as an example, how to extract sorting details and remember them for later application.

public VirtualServerModeDataLoader( VirtualServerModeConfigurationInfo configurationInfo){ // For instance, let's assume the backend supports sorting for just one field if (configurationInfo.SortInfo?.Length > 0) { SortField = configurationInfo.SortInfo[0].SortPropertyName; SortAscending = !configurationInfo.SortInfo[0].IsDesc; }}public string SortField { get; set; } = "Id";public bool SortAscending { get; set; } = true;

Data loaded from the backend is encoded as JSON in the sample, although different encodings like gRPC/Protocol Buffers would work equally well. The type DataFetchResult models the structure that is published by the backend endpoint, including the TotalCount information field.

public class DataFetchResult{ public List<OrderItem> Items { get; set; } = null!; public int TotalCount { get; set; }} 

Finally, the method GetRowsAsync handles the actual retrieval of data. It is called both on initial load (from the ConfigurationChanged handler) and on further loads (from the MoreRows handler), but the difference is only that the CurrentRowCount field of the event args differs between these applications.

The HttpClient is used to retrieve the data, passing the arguments as URL parameters for skip, take and the sorting properties. The results are deserialized from JSON and returned together with the moreRowsAvailable flag, which is interpreted by the grid as previously described.

public Task<VirtualServerModeRowsTaskResult> GetRowsAsync(VirtualServerModeRowsEventArgs e){ return Task.Run(async () => { using var client = new HttpClient(); var response = await client.GetAsync( $"{System.Configuration.ConfigurationManager.AppSettings["baseUrl"]}/data/OrderItems?skip={e.CurrentRowCount}&take={BatchSize}&sortField={SortField}&sortAscending={SortAscending}"); response.EnsureSuccessStatusCode(); var responseBody = await response.Content.ReadAsStringAsync(); var dataFetchResult = JsonSerializer.Deserialize<DataFetchResult>( responseBody, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); if (dataFetchResult is null) return new VirtualServerModeRowsTaskResult(); var moreRowsAvailable = e.CurrentRowCount + dataFetchResult.Items.Count < dataFetchResult.TotalCount; return new VirtualServerModeRowsTaskResult( dataFetchResult.Items, moreRowsAvailable); }, e.CancellationToken);}

This completes the first implementation of a Data Grid binding to an independent service. I recommend you clone the repository and try the sample for yourself!

Outlook and questions

As I mentioned before, there are two parts we will certainly add to this sample:

  1. Editing in the Data Grid, and correspondingly write access to the data through the service
  2. Authentication and authorization support.

Beyond that we are open to your suggestions for the direction this may take. Please let us know which questions are foremost in your mind after reading this and trying the sample!

Free DevExpress Products - Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We'll be happy to follow-up.

  • CodeRush for Visual Studio
  • .NET ORM Library (XPO)
Connect a WinForms Data Grid to an Arbitrary ASP.NET Core WebAPI Service Powered by EF Core (2024)

References

Top Articles
Easy Marie Rose Sauce Recipe
Keto Philly Cheesesteak Casserole Recipe
Nerdwallet Chase
Smoothie Operator Ruff Ruffman
What Is the Z-Track Injection Method?
Busted Newspaper Longview Texas
Tampa Lkq Price List
Nala Ahegao
What Was D-Day Weegy
Po Box 6726 Portland Or 97228
5 Best Vanilla Vodka co*cktails
Red Dead Redemption 2 Legendary Fish Locations Guide (“A Fisher of Fish”)
Danville Va Gotcha Paper
San Antonio Busted Newspaper
Faotp Meaning In Text
Nsu Occupational Therapy Prerequisites
Ttw Cut Content
Does Publix Pharmacy Accept Sunshine Health
Myzmanim Highland Park Nj
Uc My Bearcat Network
Carly Carrigan Family Feud Instagram - Carly Carrigan Home Facebook : The best gifs for carly family feud.
Orlando Magic Account Manager
Julie Green Ministries International On Rumble
895 Area Code Time Zone
Idaho Falls Temple Prayer Roll
Aogf Causes.benevity
Only Murders In The Building Wiki
Fast X Showtimes Near Evo Cinemas Creekside 14
Карта слов и выражений английского языка
2005 Chevy Colorado 3.5 Head Bolt Torque Specs
Emuaid Lawsuit
How Much Is 10000 Nickels
Central Valley growers, undocumented farmworkers condemn Trump's 'emergency'
Etfh Hatchery
Sessional Dates U Of T
Bianca Censo
Erie Pa Craigslist
Huskersillustrated Husker Board
Fired Dies Cancer Fired Qvc Hosts
NO CLUE: deutsche Übersetzung von NCT 127
Crossword Answers, Crossword Solver
The Nun 2 Ending Explained, Summary, Cast, Plot, Review, and More
Unblocked Games Shooters
Lowlifesymptoms Twitter
Lifetime Benefits Login
358 Edgewood Drive Denver Colorado Zillow
Jane Powell, Spirited Star of Movie Musicals ‘Royal Wedding,’ ‘Seven Brides,’ Dies at 92
Welcome to Predator Masters -- Hunting the Hunters
Grayson County Craigslist
9372034886
What stores are open on Labor Day 2024? A full list of where to shop
Barotrauma Game Wiki
Latest Posts
Article information

Author: Melvina Ondricka

Last Updated:

Views: 5778

Rating: 4.8 / 5 (68 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Melvina Ondricka

Birthday: 2000-12-23

Address: Suite 382 139 Shaniqua Locks, Paulaborough, UT 90498

Phone: +636383657021

Job: Dynamic Government Specialist

Hobby: Kite flying, Watching movies, Knitting, Model building, Reading, Wood carving, Paintball

Introduction: My name is Melvina Ondricka, I am a helpful, fancy, friendly, innocent, outstanding, courageous, thoughtful person who loves writing and wants to share my knowledge and understanding with you.