Skip to content

JohnGoldInc/EfCore.Client

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

EFCore.Client Repository

Client library for serializing and deserializing Entity Framework Core queries and saves Remotely.

A Specialized Alternative to OData, GraphQL, and other REST database integrations intended for .NET Stack and Blazor.

A choice of Serializers, You can use either Remote.Linq or Serialize.Linq

Without them this would not be possible.

Code Samples

EfCore.Client Project EfCore.Client.Tests Unit Test Project

Nuget JohnGoldInc.EntityFrameworkCore.Client 9.0.3

Blazor Page Usage

To not run afoul of the dreaded 'Cannot wait on monitors on this runtime'

Please use ToListAsync and SaveChangesAsync

@code {
    [Inject]
    required public BlazorApp1Context blazorApp1Context { get; set; }

    private List<WeatherForecast>? forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await blazorApp1Context.WeatherForecast
            .Where(wf => wf.TemperatureC > -999)
            .Include(wf => wf.PrecipitationByHour)
            .OrderBy(wf => wf.Date)
            .Take(5)
            .ToListAsync();
    }
}

Remote.Linq Client Usage

var builder = WebAssemblyHostBuilder.CreateDefault(args);

var jsonSerializerOptions = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
}.ConfigureRemoteLinq();

var httpClient = new HttpClient();

httpClient.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);

Func<string, CancellationToken, Task<string>> dataProvider = async (jsonExpression, cancellationToken) =>
{
    var response = await httpClient.PostAsync(new Uri("/api/data/query", UriKind.Relative), new StringContent(jsonExpression, MediaTypeHeaderValue.Parse("application/json"))).ConfigureAwait(false);

    if (response.StatusCode is HttpStatusCode.InternalServerError)
    {
        byte[] errorMessageData = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
        string errorMessage = Encoding.UTF8.GetString(errorMessageData);
        throw new Exception(errorMessage);
    }

    response.EnsureSuccessStatusCode();

    var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    return result ?? throw new Exception("No result.");
};

Func<IEnumerable<IUpdateEntry>, CancellationToken, Task<int>> changeSaveProvider = async (data, cancellationToken) =>
{
    var response = await httpClient.PostAsJsonAsync(new Uri("/api/data/save", UriKind.Relative), data, jsonSerializerOptions, cancellationToken).ConfigureAwait(false);

    if (response.StatusCode is HttpStatusCode.InternalServerError)
    {
        byte[] errorMessageData = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
        string errorMessage = Encoding.UTF8.GetString(errorMessageData);
        throw new Exception(errorMessage);
    }

    response.EnsureSuccessStatusCode();

    var result = await response.Content.ReadFromJsonAsync<int?>(jsonSerializerOptions).ConfigureAwait(false);
    return result ?? throw new Exception("Received empty value from server");
};

var expressionTranslator = new ExpressionTranslator();

builder.Services
    .AddDbContext<BlazorApp1Context>(options => options.UseClientDatabase(
        dataProvider,
        changeSaveProvider,
        (expression) => JsonSerializer.Serialize(expressionTranslator.TranslateExpression(expression), jsonSerializerOptions) !));

await builder.Build().RunAsync();

Remote.Linq Server Usage

    /// <summary>
    /// DataController.
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class DataController : ControllerBase
    {
        private readonly BlazorApp1Context blazorApp1Context;
        private readonly JsonSerializerOptions jsonSerializerOptions;

        /// <summary>
        /// Initializes a new instance of the <see cref="DataController"/> class.
        /// </summary>
        /// <param name="blazorApp1Context">BlazorApp1Context.</param>
        public DataController(BlazorApp1Context blazorApp1Context)
        {
            this.blazorApp1Context = blazorApp1Context;
            this.jsonSerializerOptions = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
            }.ConfigureRemoteLinq();
        }

        /// <summary>
        /// Get Data.
        /// </summary>
        /// <param name="serializedExpression">Raw Json string (made possible by RawJsonBodyInputFormatter).</param>
        /// <returns>Data.</returns>
        [HttpPost("query")]
        public ActionResult<IEnumerable<object>> Query([FromBody] string serializedExpression)
        => this.Ok(
            this.blazorApp1Context.FromClientExpression(
                (serializedExpression) => JsonSerializer.Deserialize<Remote.Linq.Expressions.Expression>(serializedExpression, this.jsonSerializerOptions)
                !.ToLinqExpression() !,
                serializedExpression) !);

        /// <summary>
        /// Save Data.
        /// </summary>
        /// <param name="entities">IEnumerable &lt; IUpdateEntry &gt;.</param>
        /// <returns>saved rows.</returns>
        [HttpPost("save")]
        public async ValueTask<ActionResult<int?>> SaveChangesAsync([FromBody] IEnumerable<IUpdateEntry> entities)
            => this.Ok(await this.blazorApp1Context.SaveChangesAsync(entities));
    }

Serialize.Linq Client Usage

var builder = WebAssemblyHostBuilder.CreateDefault(args);

var jsonSerializerOptions = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
};

var httpClient = new HttpClient();

httpClient.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);

Func<string, CancellationToken, Task<string>> dataProvider = async (jsonExpression, cancellationToken) =>
{
    var response = await httpClient.PostAsync(new Uri("/api/data/query", UriKind.Relative), new StringContent(jsonExpression, MediaTypeHeaderValue.Parse("application/json"))).ConfigureAwait(false);

    if (response.StatusCode is HttpStatusCode.InternalServerError)
    {
        byte[] errorMessageData = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
        string errorMessage = Encoding.UTF8.GetString(errorMessageData);
        throw new Exception(errorMessage);
    }

    response.EnsureSuccessStatusCode();

    var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    return result ?? throw new Exception("No result.");
};

Func<IEnumerable<IUpdateEntry>, CancellationToken, Task<int>> changeSaveProvider = async (data, cancellationToken) =>
{
    var response = await httpClient.PostAsJsonAsync(new Uri("/api/data/save", UriKind.Relative), data, jsonSerializerOptions, cancellationToken).ConfigureAwait(false);

    if (response.StatusCode is HttpStatusCode.InternalServerError)
    {
        byte[] errorMessageData = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
        string errorMessage = Encoding.UTF8.GetString(errorMessageData);
        throw new Exception(errorMessage);
    }

    response.EnsureSuccessStatusCode();

    var result = await response.Content.ReadFromJsonAsync<int?>(jsonSerializerOptions).ConfigureAwait(false);
    return result ?? throw new Exception("Received empty value from server");
};

var serializer = new ExpressionSerializer(new Serialize.Linq.Serializers.JsonSerializer());

builder.Services
    .AddDbContext<BlazorApp1Context>(options => options.UseClientDatabase(
        dataProvider,
        changeSaveProvider,
        (expression) => serializer.SerializeText(expression) !));

await builder.Build().RunAsync();

Serialize.Linq Server Usage

    /// <summary>
    /// DataController.
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class DataController : ControllerBase
    {
        private readonly BlazorApp1Context blazorApp1Context;
        private readonly ExpressionSerializer serializer;

        /// <summary>
        /// Initializes a new instance of the <see cref="DataController"/> class.
        /// </summary>
        /// <param name="blazorApp1Context">BlazorApp1Context.</param>
        public DataController(BlazorApp1Context blazorApp1Context)
        {
            this.blazorApp1Context = blazorApp1Context;
            this.serializer = new ExpressionSerializer(new JsonSerializer());
        }

        /// <summary>
        /// Get Data.
        /// </summary>
        /// <param name="serializedExpression">Raw Json string (made possible by RawJsonBodyInputFormatter).</param>
        /// <returns>Data.</returns>
        [HttpPost("query")]
        public ActionResult<IEnumerable<object>> Query([FromBody] string serializedExpression)
            => this.Ok(this.blazorApp1Context.FromClientExpression(
                (serializedExpression) => this.serializer.DeserializeText(serializedExpression),
                serializedExpression));

        /// <summary>
        /// Save Data.
        /// </summary>
        /// <param name="entities">IEnumerable &lt; IUpdateEntry &gt;.</param>
        /// <returns>saved rows.</returns>
        [HttpPost("save")]
        public async ValueTask<ActionResult<int?>> SaveChangesAsync([FromBody] IEnumerable<IUpdateEntry> entities)
            => this.Ok(await this.blazorApp1Context.SaveChangesAsync(entities));
    }

About

EF Core Client

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Languages

  • C# 99.3%
  • PowerShell 0.3%
  • TSQL 0.2%
  • Shell 0.2%
  • CMake 0.0%
  • Visual Basic .NET 0.0%