Where It All Started.

Where It All Started.

Life, Stock Trading, Investments, Business and Startup. Most are programming stuff.

Tag: csharp

Quick Simple GraphQL Provider On ASP.NET Core 5.0

My most recent project tackles implementing GraphQL1 provider using C#. This is my first time implementing this stuff on C#, but I’ve already implemented it before on Java and also on Rust. This are the simple things I’ve learned while implementing a simple (hello world) GraphQL server on C#.


In your thoughts, you need to be selective. Thoughts are powerful vehicles of attention. Only think positive thoughts about yourself and your endeavors, and think well of the endeavors of others.

— Frederick Lenz.

Come on join me and lets dive in! ☄

Prerequisites

First of all, you must have a .NET Core 5.0 SDK (Software Development Kit) installed in your computer and also I assumed you are currently running Windows 10 or Linux with proper environment set.

If you are on Windows 10 and already have a Visual Studio2 2019, just update it to the most recent version, that way would ensure your system to have the latest .NET Core SDK version.

So where do we start?

First we create our ASP.NET3 Web API project on the command-line. Execute the command below to create the project.

dotnet new web -f net5.0 --no-https --name GqlNet5Demo

This command specifically creates a project with .NET Core 5.0 as target. The --no-https flag specifies we will be only working with non-SSL HTTP server config, and the type of project we generate is web (from an empty ASP.NET core template).

If the command is successful, we should now be able to see the folder GqlNet5Demo. Change directory on to it so we could start our changes to the template project.

cd GqlNet5Demo

Inside the project folder, we need to add now the base core of GraphQL.Net library and its default deserializer. Execute the command in an open shell:

dotnet add package GraphQL.Server.Transports.AspNetCore
dotnet add package GraphQL.Server.Transports.AspNetCore.SystemTextJson

Then this next package is optional only if you need GraphQL Websocket support, specially useful if you are implementing a subscription based GraphQL API. Anyways, for our project lets add this dependency.

dotnet add package GraphQL.Server.Transports.WebSockets

Also, add this other package which helps in debugging GraphQL statements on browser. This will install an embedded GraphQL Playground on our demo project, just don’t forget to remove this on a production server.

dotnet add package GraphQL.Server.Ui.Playground

After all those package installed, lets move on now on to editing our first file. Let’s create the file first named EhloSchema.cs and place it on the root folder. On the file, import the library namespace that we will be using.

using  GraphQL;
using  GraphQL.Resolvers;
using  GraphQL.Types;

After importing the needed libraries, we implement our root query type which will contain the query structure of our GraphQL schema. The query type is useful if you want to only read data.

public sealed class EhloQuery : ObjectGraphType
{
    public EhloQuery()
    {
        Field<StringGraphType>("greet", description: "A type that returns a simple hello world string", resolve: context => "Hello, World");
    }
}

From the above we also implemented our first query type named “greet” which can be then called like this on the GraphQL playground.

query {
  greet
}

The instruction on creating a GraphQL type starts with Field or AddField following by type of field that will be returned and its required field the name and of course resolver.

If called on the GraphQL playground it would output a JSON with a data message containing “Hello, World”. To be able to run the GraphQL playground, let’s continue on the tutorial.

Still on the file EhloSchema.cs, add this instructions below in order for us to create our first schema. This schema will map the Query to our created class EhloQuery instance.

public sealed class EhloSchema : Schema
{
    public EhloSchema(IServiceProvider provider) : base(provider)
    {
        Query = new EhloQuery();
    }
}

That’s all for now on the EhloSchema.cs file! This is the most basic requirement needed in order to create a super basic GraphQL server.

Let’s now start modifying the Startup.cs file. Add this new imports which are needed for our constructor.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;

This two imports allows us to use the IConfiguration and the IWebHostEnvironment abstract interface and their respective allowable methods. The next thing is implement our constructor and class scope variables. See below on what to implement.

public IConfiguration Configuration { get; }
public IWebHostEnvironment Environment { get; }

public Startup(IConfiguration configuration, IWebHostEnvironment environment)
{
    Configuration = configuration;
    Environment = environment;
}

After implementing the constructor, we also need to import the GraphQL base library.

using GraphQL.Server;

Then on the ConfigureServices method we add and build the GraphQL service.

services
    .AddSingleton<EhloSchema>()
    .AddGraphQL((options, provider) =>
    {
        options.EnableMetrics = Environment.IsDevelopment();

        var logger = provider.GetRequiredService<ILogger<Startup>>();
        options.UnhandledExceptionDelegate = ctx => logger.LogError("{Error} occured", ctx.OriginalException.Message);
    })
    .AddSystemTextJson(deserializerSettings => { }, serializerSettings => { })
    .AddErrorInfoProvider(opt => opt.ExposeExceptionStackTrace = Environment.IsDevelopment())
    .AddWebSockets()
    .AddDataLoader()
    .AddGraphTypes(typeof(EhloSchema));

If you look at the instructions above we set and add first our Schema as a singleton class that will be initialize once. Then we set parameters to our GraphQL server, and set its default deserializer. Also, don’t forget we add websocket and dataloader to it. The dataloader is useful to prevent n+1 attacks that happen on GraphQL servers. More information can be found on this link.

We now need to implement calls to respective middlewares and activate the services. First is to activate the websocket protocol on our server, then also enable the GraphQL websocket middleware to inject our schema. The /graphql is the endpoint where the schema will be deployed.

app.UseWebSockets();
app.UseGraphQLWebSockets<EhloSchema>("/graphql");

app.UseGraphQL<EhloSchema>("/graphql");
app.UseGraphQLPlayground();

Don’t forget we need to activate also our GraphQL playground so we can use it on our demo GraphQL server. Here’s the full source of our Startup.cs, check whether if you forgot or missed something.

using GraphQL.Server;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace GqlNet5Demo
{
    public class Startup
    {

        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }

        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services
                .AddSingleton<EhloSchema>()
                .AddGraphQL((options, provider) =>
                {
                    options.EnableMetrics = Environment.IsDevelopment();

                    var logger = provider.GetRequiredService<ILogger<Startup>>();
                    options.UnhandledExceptionDelegate = ctx => logger.LogError("{Error} occured", ctx.OriginalException.Message);
                })
                .AddSystemTextJson(deserializerSettings => { }, serializerSettings => { })
                .AddErrorInfoProvider(opt => opt.ExposeExceptionStackTrace = Environment.IsDevelopment())
                .AddWebSockets()
                .AddDataLoader()
                .AddGraphTypes(typeof(EhloSchema));
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseWebSockets();
            app.UseGraphQLWebSockets<EhloSchema>("/graphql");

            app.UseGraphQL<EhloSchema>("/graphql");
            app.UseGraphQLPlayground();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
    }
}

Now its time to run our ASP.NET GraphQL API server. Do that by executing the command on our previous opened shell:

dotnet run

If its all successful, then you should head out to http://localhost:<port>/ui/playground to access the GraphQL Playground. The <port> field pertains to the port indicated in the applicationUrl inside launchSettings.json that can be found inside your project.

If you encounter any problem, just try to re-check all the things we did above or check the full source at bottom of this article.

Our next step is to implement a complex query structure. We first need to implement this classes in our EhloSchema.cs.

public sealed class Message
{
    public string Content { get; set; }
    public DateTime CreatedAt { get; set; }
}

public sealed class MessageType : ObjectGraphType<Message>
{
    public MessageType()
    {
        Field(o => o.Content);
        Field(o => o.CreatedAt, type: typeof(DateTimeGraphType));
    }
}

This will create two classes which are Message and MessageType. The Message class will be our model class that will store data temporary into our program’s memory. And the MessageType will be the conversion from GraphQL type to our model class which is Message.

After that we need to implement this new field type on our EchoQuery constructor. This a simple example or returning low-complex type query on our server.

Field<MessageType>("greetComplex", description: "A type that returns a complex data", resolve: context =>
{
    return new Message
    {
        Content = "Hello, World",
        CreatedAt = DateTime.UtcNow,
    };
});

Then to test it, we need to access our GraphQL Playground to execute this GraphQL statement.

query {
  greetComplex {
    content
    createdAt
  }
}

If everything is okay, it would return a JSON containing no error message and correct response with structure similar to Message data structure.

Next, we move to mutation type. The mutation type is specifically useful if you want to modify data, in CRUD it will be the CUD (Create, Update and Delete). We now need to create the root mutation type, just implement the following class below.

public sealed class EhloMutation : ObjectGraphType<object>
{
    public EhloMutation()
    {
        Field<StringGraphType>("greetMe",
                arguments: new QueryArguments(
                    new QueryArgument<StringGraphType>
                    {
                        Name = "name"
                    }),
                resolve: context =>
                {
                    string name = context.GetArgument<string>("name");
                    string message = $"Hello {name}!";
                    return message;
                });
    }
}

On the constructor, you’ll see we also implemented a field type that will return string and accepts one string argument. We also need to initialize this mutation class that we created on our main schema. Add the line below in the constructor of our EhloSchema class.

Mutation = new EhloMutation();

After implementing the mutation, build and run the whole project and go to GraphQL Playground to test our mutation. In our case the mutation doesn’t modify any stored data but just return a simple string appended by argument. The mutation statement starts with mutation instead of query.

mutation {
  greetMe(name: "Wick")
}

Next, we implement GraphQL subscription. The subscription on GraphQL is mostly used on events (e.g. someone registered, login notifications, system notifications, etc.) but mostly it can be use on anything that can be streamed.

Let’s implement it now on our EhloSchema.cs file.

public sealed class EhloSubscription : ObjectGraphType<object>
{
    public ISubject<string> greetValues = new ReplaySubject<string>(1);

    public EhloSubscription()
    {
        AddField(new EventStreamFieldType
        {
            Name = "greetCalled",
            Type = typeof(StringGraphType),
            Resolver = new FuncFieldResolver<string>(context =>
            {
                var message = context.Source as string;
                return message;
            }),
            Subscriber = new EventStreamResolver<string>(context =>
            {
                return greetValues.Select(message => message).AsObservable();
            }),
        });

        greetValues.OnNext("Hello, World");
    }
}

Similar to the Query and Mutation, will only implement simple event stream resolver and a subscriber listener. The greetCalled method will just return a simple string upon call on OnNext. Then on EhloSchema constructor same in mutation we also link the root subscription type.

Subscription = new EhloSubscription();

Then we test it on GraphQL Playground. In order to call a subscription type, we start by using the subscription statement.

subscription {
  greetCalled
}

Here’s the full source code of EhloSchema.cs file. You can re-check all the changes you did before and compare it to this. Also on this source, you’ll find that we also implemented a low-complex method in mutation that will return a structure on mutation. The mutation also accepts custom structure named MessageInputType.

using GraphQL;
using GraphQL.Resolvers;
using GraphQL.Types;
using System;
using System.Reactive.Linq;
using System.Reactive.Subjects;

namespace GqlNet5Demo
{
    public sealed class EhloSchema : Schema
    {
        public EhloSchema(IServiceProvider provider) : base(provider)
        {
            Query = new EhloQuery();
            Mutation = new EhloMutation();
            Subscription = new EhloSubscription();
        }
    }

    public sealed class Message
    {
        public string Content { get; set; }
        public DateTime CreatedAt { get; set; }
    }

    public sealed class MessageType : ObjectGraphType<Message>
    {
        public MessageType()
        {
            Field(o => o.Content);
            Field(o => o.CreatedAt, type: typeof(DateTimeGraphType));
        }
    }

    public sealed class EhloQuery : ObjectGraphType
    {
        public EhloQuery()
        {
            Field<StringGraphType>("greet", description: "A type that returns a simple hello world string", resolve: context => "Hello, World");
            Field<MessageType>("greetComplex", description: "A type that returns a complex data", resolve: context =>
            {
                return new Message
                {
                    Content = "Hello, World",
                    CreatedAt = DateTime.UtcNow,
                };
            });
        }
    }

    public sealed class MessageInputType : InputObjectGraphType
    {
        public MessageInputType()
        {
            Field<StringGraphType>("content");
            Field<DateTimeGraphType>("createdAt");
        }
    }

    public sealed class EhloMutation : ObjectGraphType<object>
    {
        public EhloMutation()
        {
            Field<StringGraphType>("greetMe",
                    arguments: new QueryArguments(
                        new QueryArgument<StringGraphType>
                        {
                            Name = "name"
                        }),
                    resolve: context =>
                    {
                        string name = context.GetArgument<string>("name");
                        string message = $"Hello {name}!";
                        return message;
                    });

            Field<MessageType>("echoMessageComplex",
                    arguments: new QueryArguments(
                        new QueryArgument<MessageInputType>
                        {
                            Name = "message"
                        }),
                    resolve: context =>
                    {
                        Message message = context.GetArgument<Message>("message");
                        return message;
                    });
        }
    }

    public sealed class EhloSubscription : ObjectGraphType<object>
    {
        public ISubject<string> greetValues = new ReplaySubject<string>(1);

        public EhloSubscription()
        {
            AddField(new EventStreamFieldType
            {
                Name = "greetCalled",
                Type = typeof(StringGraphType),
                Resolver = new FuncFieldResolver<string>(context =>
                {
                    var message = context.Source as string;
                    return message;
                }),
                Subscriber = new EventStreamResolver<string>(context =>
                {
                    return greetValues.Select(message => message).AsObservable();
                }),
            });

            greetValues.OnNext("Hello, World");
        }
    }
}

That’s all guys, after checking – build and run the whole project. 🙌

Conclusion

Implementing GraphQL seems a bit daunting at first, but if you know the internals of it you’ll reap many benefits by using it versus normal REST API endpoints. It’s not for this article to discuss the pros and cons of that. Anyways, as you can see its bit easy now to implement GraphQL on C# but I don’t see many enterprise switching over it as it will probably disrupt some of their services.

Let me know in the comments if you have questions or queries, you can also DM me directly.

Follow me for similar article, tips, and tricks ❤.


  1. GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. GraphQL was developed internally by Facebook in 2012 before being publicly released in 2015. ↩︎
  2. Microsoft Visual Studio is an integrated development environment (IDE) from Microsoft. It is used to develop computer programs, as well as websites, web apps, web services and mobile apps. Visual Studio uses Microsoft software development platforms such as Windows API, Windows Forms, Windows Presentation Foundation, Windows Store and Microsoft Silverlight. It can produce both native code and managed code. ↩︎
  3. ASP.NET is an open-source, server-side web-application framework designed for web development to produce dynamic web pages. It was developed by Microsoft to allow programmers to build dynamic web sites, applications and services. ↩︎

Sending Email Using MailKit in ASP.NET Core Web API

You do not need to know precisely what is happening, or exactly where it is all going. What you need is to recognize the possibilities and challenges offered by the present moment, and to embrace them with courage, faith and hope.

— Thomas Merton.

Hey guys, recently I’ve been working on an ASP.NET Core project that needed email services to send reports. And I’ve been dumbfounded by some tutorial on how they implemented the email service functionality. Some are over complicated while others were over simplified.

So here I am creating yet another tutorial for sending email using MailKit and .NET Core.

Let’s jump in!

Prerequisites

First of all, you must have a .NET Core 3.1 SDK (Software Development Kit) installed in your computer and also I assumed you are currently running Windows 10 or some Linux with proper environment set.

And MailKit on which this package becomes a de-facto standard in sending emails as its being preferred and recommended by Microsoft in their tutorials over the standard System.Mail.Net .

So where do we start?

First we create our ASP.NET Web API project on the command-line. Execute the command below to create the project.

dotnet new webapi --name MyProject

The dotnet new command creates a project folder base on the declared template on which in our case is webapi . The --name flag indicates that the next argument would be its output path and project name.

After that go inside the project root folder. Then we add a reference to MailKit nuget package to project. If the project already reference the MailKit then try running dotnet restore to get and update the reference assemblies locally.

dotnet add package MailKit

Then we create and add the SMTP ( Simple Mail Transfer Protocol) settings to the appsettings.json and appsettings.Development.json . In the example below I’ve used Gmail setup, just fill it up with your own account settings and be sure to use an app password in the password field.

If you have a custom SMTP server just replace the port and server as well as other needed fields.

"SmtpSettings": {
  "Server": "smtp.gmail.com",
  "Port": 587,
  "SenderName": "My Name",
  "SenderEmail": "<my-account-user>@gmail.com",
  "Username": "<my-account-user>@gmail.com",
  "Password": "<my-account-password>"
}

Create an entity structure which will store the SMTP settings. This structure will receive the settings we setup above in the appsettings.json .

namespace MyProject.Entities
{
    public class SmtpSettings
    {
        public string Server { get; set; }
        public int Port { get; set; }
        public string SenderName { get; set; }
        public string SenderEmail { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
    }
}

Next is we setup the mailer interface to provide to our controllers. This IMailer interface exposes one method just to send email asynchronously. You can add more methods but I feel one is enough.

public interface IMailer
{
    Task SendEmailAsync(string email, string subject, string body);
}

Implement the mailer class structure with basic defaults, and after that try and build it, check if there are any error. Check if linting provides any warning or programming mistakes.

public class Mailer : IMailer
{
    public async Task SendEmailAsync(string email, string subject, string body)
    {
        await Task.Completed;
    }
}

If all things implemented properly, we create the template sender functionality. This method will accept recipient email, the subject of the email and the message body.

using MailKit.Net.Smtp;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using MimeKit;
using System;
using System.Threading.Tasks;
using MyProject.Entities;

namespace MyProject.Services
{
    public interface IMailer
    {
        Task SendEmailAsync(string email, string subject, string body);
    }

    public class Mailer : IMailer
    {
        private readonly SmtpSettings _smtpSettings;
        private readonly IWebHostEnvironment _env;

        public Mailer(IOptions<SmtpSettings> smtpSettings, IWebHostEnvironment env)
        {
            _smtpSettings = smtpSettings.Value;
            _env = env;
        }

        public async Task SendEmailAsync(string email, string subject, string body)
        {
            try
            {
                var message = new MimeMessage();
                message.From.Add(new MailboxAddress(_smtpSettings.SenderName, _smtpSettings.SenderEmail));
                message.To.Add(new MailboxAddress(email));
                message.Subject = subject;
                message.Body = new TextPart("html")
                {
                    Text = body
                };

                using (var client = new SmtpClient())
                {
                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;

                    if (_env.IsDevelopment())
                    {
                        await client.ConnectAsync(_smtpSettings.Server, _smtpSettings.Port, true);
                    }
                    else
                    {
                        await client.ConnectAsync(_smtpSettings.Server);
                    }

                    await client.AuthenticateAsync(_smtpSettings.Username, _smtpSettings.Password);
                    await client.SendAsync(message);
                    await client.DisconnectAsync(true);
                }
            }
            catch (Exception e)
            {
                throw new InvalidOperationException(e.Message);
            }
        }
    }
}

In the source above we create first a MimeMessage which contains all the needed data for an email body and header, it contains MAIL FROM, RCPT TO , and DATA .

After that we setup SMTP client with the fields we setup in our appsettings.json . The client.AuthenticateAsync can be omitted if the SMTP server doesn’t have an authentication flow.

When everything is done in Mailer, we now edit the Startup.cs file in project root folder. We then insert SMTP settings parser and initialize a singleton object that will handle mail service in ConfigureServices .

services.Configure<SmtpSettings>(Configuration.GetSection("SmtpSettings"));
services.AddSingleton<IMailer, Mailer>();

After setting up the services in startup, we head onto the WeatherForecastController.cs which is included when we bootstrap the project. This files are part of the webapi template, you can use your own custom controller function to call on the IMailer interface.

private readonly IMailer _mailer;

public WeatherForecastController(ILogger<WeatherForecastController> logger, IMailer mailer)
{
    _logger = logger;
    _mailer = mailer;
}

Look on how we add the IMailer mailer variable as this becomes available for us when we did setup and add a singleton object in our startup. We then store the variable in our private variable for future usage.

We also create another method to handle new route /export for sending temporary weather report. Change it according to your own setup.

[HttpGet]
[Route("export")]
public async Task<IActionResult> ExportWeatherReport()
{
    await _mailer.SendEmailAsync("[email protected]", "Weather Report", "Detailed Weather Report");
    return NoContent();
}

In the code above we simply insert the mailer and called our exposed method SendEmailAsync . Check the full source below for details on what to packages needed to import on the module.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using MyProject.Services;

namespace MyProject.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;
        private readonly IMailer _mailer;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, IMailer mailer)
        {
            _logger = logger;
            _mailer = mailer;
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }

        [HttpGet]
        [Route("export")]
        public async Task<IActionResult> ExportWeatherReport()
        {
            await _mailer.SendEmailAsync("[email protected]", "Weather Report", "Detailed Weather Report");
            return NoContent();
        }
    }
}

When everything’s done we build and test the web API project. Execute the code below to check if there are any errors.

dotnet build

Then deploy or publish it on IIS (Internet Information Services), or rather just run it in isolated form which you can use dotnet run .

Conclusion

If you’re doing an email service always consider to make it as simple as possible to avoid any unintended bugs. Sending emails has never been easier this time around and you don’t need complicated flows as we switch to MailKit.

You can found the complete repository here .

Follow me for similar article, tips, and tricks ❤.

C# .NET Projects Can Be Compiled and Run in MacOS or Linux

My primary goal of hacking was the intellectual curiosity, the seduction of adventure.

— Kevin Mitnick.

Before I never thought that a .NET solution project can be compiled and run on Linux. But as I’ve checked the GitHub of dotnet-core, I found there were many ways to do it.

First is through Mono, which is a compatible open source alternative to the .NET Framework (the latter is a proprietary of Microsoft). You can create WPF (Windows Presentation Foundation) forms using it and other UI intensive .NET projects. Mono is sponsored by Microsoft, but it is unofficially supported.

The other solution is, if your working on a .NET core project you’ll be using a dotnet-core. Microsoft published last 2014 an open source .NET SDK (Software Development Kit) (bare bones) which was derived from ASP.NET, they’ve called it dotnet-core. Basically, it is a stripped down version of .NET framework without all the heavy UI and forms. The project itself is modular and can be compiled in different platforms.

So if you’re planning to use C# or a .NET dependent language, don’t be afraid as it can be run and created using different platforms.

If you’re planning to install the package on Arch here is the command:

pacman -Sy dotnet-core

Or check the mono flavor:

pacman -Sy mono

That’s it guys, a brand new knowledge for me. Probably on my next project I’ll try to use .NET Core. 🤔 Hope you guys, enjoyed this article and as always live life.