Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 83 additions & 88 deletions examples/Ticketer/Client/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,113 +16,108 @@

#endregion

using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Grpc.Net.Client;
using Ticket;

namespace Client
{
public class Program
{
private const string Address = "https://localhost:5001";
using var channel = GrpcChannel.ForAddress(Address);
var client = new Ticketer.TicketerClient(channel);

static async Task Main(string[] args)
{
using var channel = GrpcChannel.ForAddress(Address);
var client = new Ticketer.TicketerClient(channel);
Console.WriteLine("gRPC Ticketer");
Console.WriteLine();
Console.WriteLine("Press a key:");
Console.WriteLine("1: Get available tickets");
Console.WriteLine("2: Purchase ticket");
Console.WriteLine("3: Authenticate");
Console.WriteLine("4: Exit");
Console.WriteLine();

Console.WriteLine("gRPC Ticketer");
Console.WriteLine();
Console.WriteLine("Press a key:");
Console.WriteLine("1: Get available tickets");
Console.WriteLine("2: Purchase ticket");
Console.WriteLine("3: Authenticate");
Console.WriteLine("4: Exit");
Console.WriteLine();
string? token = null;

string? token = null;
var exiting = false;
while (!exiting)
{
var consoleKeyInfo = Console.ReadKey(intercept: true);
switch (consoleKeyInfo.KeyChar)
{
case '1':
await GetAvailableTickets(client);
break;
case '2':
await PurchaseTicket(client, token);
break;
case '3':
token = await Authenticate();
break;
case '4':
exiting = true;
break;
}
}

var exiting = false;
while (!exiting)
{
var consoleKeyInfo = Console.ReadKey(intercept: true);
switch (consoleKeyInfo.KeyChar)
{
case '1':
await GetAvailableTickets(client);
break;
case '2':
await PurchaseTicket(client, token);
break;
case '3':
token = await Authenticate();
break;
case '4':
exiting = true;
break;
}
}
Console.WriteLine("Exiting");

Console.WriteLine("Exiting");
}
static async Task<string> Authenticate()
{
Console.WriteLine($"Authenticating as {Environment.UserName}...");
using var httpClient = new HttpClient();
using var request = new HttpRequestMessage
{
RequestUri = new Uri($"{Address}/generateJwtToken?name={HttpUtility.UrlEncode(Environment.UserName)}"),
Method = HttpMethod.Get,
Version = new Version(2, 0)
};
using var tokenResponse = await httpClient.SendAsync(request);
tokenResponse.EnsureSuccessStatusCode();

private static async Task<string> Authenticate()
{
Console.WriteLine($"Authenticating as {Environment.UserName}...");
using var httpClient = new HttpClient();
using var request = new HttpRequestMessage
{
RequestUri = new Uri($"{Address}/generateJwtToken?name={HttpUtility.UrlEncode(Environment.UserName)}"),
Method = HttpMethod.Get,
Version = new Version(2, 0)
};
using var tokenResponse = await httpClient.SendAsync(request);
tokenResponse.EnsureSuccessStatusCode();
var token = await tokenResponse.Content.ReadAsStringAsync();
Console.WriteLine("Successfully authenticated.");

var token = await tokenResponse.Content.ReadAsStringAsync();
Console.WriteLine("Successfully authenticated.");
return token;
}

return token;
static async Task PurchaseTicket(Ticketer.TicketerClient client, string? token)
{
Console.WriteLine("Purchasing ticket...");
try
{
Metadata? headers = null;
if (token != null)
{
headers = new Metadata();
headers.Add("Authorization", $"Bearer {token}");
}

private static async Task PurchaseTicket(Ticketer.TicketerClient client, string? token)
var response = await client.BuyTicketsAsync(new BuyTicketsRequest { Count = 1 }, headers);
if (response.Success)
{
Console.WriteLine("Purchasing ticket...");
try
{
Metadata? headers = null;
if (token != null)
{
headers = new Metadata();
headers.Add("Authorization", $"Bearer {token}");
}

var response = await client.BuyTicketsAsync(new BuyTicketsRequest { Count = 1 }, headers);
if (response.Success)
{
Console.WriteLine("Purchase successful.");
}
else
{
Console.WriteLine("Purchase failed. No tickets available.");
}
}
catch (Exception ex)
{
Console.WriteLine("Error purchasing ticket." + Environment.NewLine + ex.ToString());
}
Console.WriteLine("Purchase successful.");
}

private static async Task GetAvailableTickets(Ticketer.TicketerClient client)
else
{
Console.WriteLine("Getting available ticket count...");
var response = await client.GetAvailableTicketsAsync(new Empty());
Console.WriteLine("Available ticket count: " + response.Count);
Console.WriteLine("Purchase failed. No tickets available.");
}
}
catch (RpcException ex)
{
Console.WriteLine($"Error purchasing ticket: {ex.Status.StatusCode}");
}
catch (Exception ex)
{
Console.WriteLine($"Error purchasing ticket.{Environment.NewLine}{ex.ToString()}");
}
}

static async Task GetAvailableTickets(Ticketer.TicketerClient client)
{
Console.WriteLine("Getting available ticket count...");
var response = await client.GetAvailableTicketsAsync(new Empty());
Console.WriteLine("Available ticket count: " + response.Count);
}

public partial class Program
{
private const string Address = "https://localhost:5001";
}
71 changes: 56 additions & 15 deletions examples/Ticketer/Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,64 @@

#endregion

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Server;

namespace Server
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
builder.Services.AddSingleton<TicketRepository>();

builder.Services.AddAuthorization(options =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered using the new AuthorizationBuilder model here. Should be something like this:

services.AddAuthorization().AddPolicy(
  JwtBearerDefaults.AuthenticationScheme,
  policy => {
    policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
    policy.RequireClaim(ClaimTypes.Name);
  });

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't available for me. Perhaps the .NET 7 version with it isn't out yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting...they should've been a part of the preview7 release...

In any case, not a huge deal...

{
options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
{
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
policy.RequireClaim(ClaimTypes.Name);
});
});
builder.Services.AddAuthentication()
.AddJwtBearer(options =>
{
options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateActor = false,
ValidateLifetime = true,
IssuerSigningKey = SecurityKey
};
});

var app = builder.Build();

app.MapGrpcService<TicketerService>();

app.MapGet("/generateJwtToken", context =>
{
public class Program
return context.Response.WriteAsync(GenerateJwtToken(context.Request.Query["name"]!));
});

app.Run();

static string GenerateJwtToken(string name)
{
if (string.IsNullOrEmpty(name))
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
throw new InvalidOperationException("Name is not specified.");
}

var claims = new[] { new Claim(ClaimTypes.Name, name) };
var credentials = new SigningCredentials(SecurityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken("ExampleServer", "ExampleClients", claims, expires: DateTime.Now.AddSeconds(60), signingCredentials: credentials);
return JwtTokenHandler.WriteToken(token);
}

public partial class Program
{
private static readonly JwtSecurityTokenHandler JwtTokenHandler = new JwtSecurityTokenHandler();
private static readonly SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(Guid.NewGuid().ToByteArray());
}
101 changes: 0 additions & 101 deletions examples/Ticketer/Server/Startup.cs

This file was deleted.

Loading