Method injection

In the following example, you are going to add a new service for handling game invitations and updating the Tic-Tac-Toe application. This facilitates email communication, which is used for contacting other users to join a game, while using method injection:

  1. Add a new service called GameInvitationService in the Services folder for managing game invitations (adding, updating, removing, and more):
public class GameInvitationService 
{ 
  private static ConcurrentBag<GameInvitationModel>  
_gameInvitations; public GameInvitationService(){ _gameInvitations = new ConcurrentBag<GameInvitationModel>();} public Task<GameInvitationModel> Add(GameInvitationModel
gameInvitationModel) { gameInvitationModel.Id = Guid.NewGuid(); _gameInvitations.Add(gameInvitationModel); return Task.FromResult(gameInvitationModel); }
public Task Update(GameInvitationModel gameInvitationModel) { _gameInvitations = new ConcurrentBag<GameInvitationModel>
(_gameInvitations.Where(x => x.Id != gameInvitationModel.Id)) { gameInvitationModel }; return Task.CompletedTask; } public Task<GameInvitationModel> Get(Guid id) { return Task.FromResult(_gameInvitations.FirstOrDefault(x =>
x.Id == id)); }
}
  1. Extract the IGameInvitationService interface:
  1. Add the new game invitation service to the ConfigureServices method of the Startup class (we want a single application instance, so add it as a singleton):
        services.AddSingleton<IGameInvitationService, 
GameInvitationService>();

  1. Update the Index method in GameInvitationController and inject an instance of the game invitation service via method injection using the RequestServices provider:
      
public IActionResult Index(GameInvitationModel gameInvitationModel, [FromServices]IEmailService emailService)
{
 var gameInvitationService = Request.HttpContext.RequestServices.GetService             <IGameInvitationService>();
  if (ModelState.IsValid) {
     emailService.SendEmail(gameInvitationModel.EmailTo,
_stringLocalizer["Invitation for playing a Tic-Tac-Toe game"], _stringLocalizer[$"Hello, you have been invited to play the
Tic-Tac-Toe game by {0}. For joining the game, please
click here {1}", gameInvitationModel.InvitedBy,
Url.Action("GameInvitationConfirmation", GameInvitation",
new { gameInvitationModel.InvitedBy,
gameInvitationModel.EmailTo }, Request.Scheme,
Request.Host.ToString())]); var invitation = gameInvitationService.Add
(gameInvitationModel).Result; return RedirectToAction("GameInvitationConfirmation",
new { id = invitation.Id }); } return View(gameInvitationModel);
}
Don't forget to add the following using statement at the beginning of the class: using Microsoft.Extensions.DependencyInjection;, If you don't, the .GetService<IGameInvitationService>(); method can't be used and you will get build errors.
  1. Add a new method called GameInvitationConfirmation to GameInvitationController:
        [HttpGet] 
        public IActionResult GameInvitationConfirmation(Guid id,
[FromServices]IGameInvitationService gameInvitationService) { var gameInvitation = gameInvitationService.Get(id).Result; return View(gameInvitation); }

  1. Create a new view for the GameInvitationConfirmation method you added previously. This will display a waiting message to the user:
        @model TicTacToe.Models.GameInvitationModel 
        @{ 
           ViewData["Title"] = "GameInvitationConfirmation"; 
           Layout = "~/Views/Shared/_Layout.cshtml"; 
        } 
        <h1>@Localizer["You have invited {0} to play
a Tic-Tac-Toe game
with you, please wait until the user is connected",
Model.EmailTo]</h1> @section Scripts{ <script> $(document).ready(function () { GameInvitationConfirmation('@Model.Id'); }); </script> }
  1. Add a new method called GameInvitationConfirmation to the scripts1.js file. You can use the same basic structure we used for the existing EmailConfirmation method:
        function GameInvitationConfirmation(id) { 
          if (window.WebSocket) { 
            alert("Websockets are enabled"); 
            openSocket(id, "GameInvitation"); 
          } 
          else { 
            alert("Websockets are not enabled"); 
            interval = setInterval(() => { 
              CheckGameInvitationConfirmationStatus(id); 
            }, 5000); 
          } 
        }
  1. Add a method called CheckGameInvitationConfirmationStatus to the scripts2.js file. You can use the same basic structure we used for the existing CheckEmailConfirmationStatus method:
        function CheckGameInvitationConfirmationStatus(id) { 
          $.get("/GameInvitationConfirmation?id=" + id,
function (data) { if (data.result === "OK") { if (interval !== null) clearInterval(interval); window.location.href = "/GameSession/Index/" + id; } }); }
  1. Update the openSocket method in the scripts2.js file and add the specific game invitation case:
...
if (strAction == "Email") { 
  wsUri = protocol + "//" + window.location.host + "/CheckEmailConfirmationStatus"; 
  operation = "CheckEmailConfirmationStatus"; 
} 
else if (strAction == "GameInvitation") { 
  wsUri = protocol + "//" + window.location.host + "/GameInvitationConfirmation"; 
  operation = "CheckGameInvitationConfirmationStatus"; 
} 
 
var socket = new WebSocket(wsUri); 
socket.onmessage = function (response) { console.log(response); 
  if (strAction == "Email" && response.data == "OK") { 
    window.location.href = "/GameInvitation?email=" + parameter; 
  }else if (strAction == "GameInvitation") { 
    var data = $.parseJSON(response.data); 
 
  if (data.Result == "OK") window.location.href = "/GameSession/Index/" + data.Id; }  }; 
 ...
         
  1. Add a new method called ProcessGameInvitationConfirmation in the communication middleware. This will process game invitation requests without using WebSockets for browsers that don't support this feature:
private async Task ProcessGameInvitationConfirmation(HttpContext context) 
{ 
  var id = context.Request.Query["id"]; 
  if (string.IsNullOrEmpty(id))await context.
Response.WriteAsync("BadRequest:Id is required"); var gameInvitationService = context.RequestServices.GetService
<IGameInvitationService>(); var gameInvitationModel = await
gameInvitationService.Get(Guid.Parse(id)); if (gameInvitationModel.IsConfirmed) await
context.Response.WriteAsync(
JsonConvert.SerializeObject(new { Result = "OK", Email = gameInvitationModel.InvitedBy,
gameInvitationModel.EmailTo })); else { await context.Response.WriteAsync(
"WaitGameInvitationConfirmation"); } }
Don't forget to add the following using statement at the beginning of the class:
using Microsoft.Extensions.DependencyInjection;.
  1. Add a new method called ProcessGameInvitationConfirmation with additional parameters to the communication middleware. This will process game invitation requests while using WebSockets for the browsers that support this:
private async Task ProcessGameInvitationConfirmation(HttpContext context,
WebSocket webSocket, CancellationToken ct,
string parameters) { var gameInvitationService = context.RequestServices.GetService
<IGameInvitationService>(); var id = Guid.Parse(parameters); var gameInvitationModel = await gameInvitationService.Get(id); while (!ct.IsCancellationRequested && !webSocket.
CloseStatus.HasValue &&
gameInvitationModel?.IsConfirmed == false) {
await SendStringAsync(webSocket, JsonConvert.

SerializeObject(new { Result = "OK", Email = gameInvitationModel.InvitedBy,
gameInvitationModel.EmailTo, gameInvitationModel.Id }), ct); Task.Delay(500).Wait(); gameInvitationModel = await gameInvitationService.Get(id); } }
  1. Update the Invoke method in the communication middleware. This will work with email confirmations and game invitation confirmations from now on, with and without WebSockets:
public async Task Invoke(HttpContext context) 
{ 
  if (context.WebSockets.IsWebSocketRequest) 
  { 
    ... 
    switch (command.Operation.ToString()) 
    { 
      ... 
      case "CheckGameInvitationConfirmationStatus": 
      { await 
ProcessGameInvitationConfirmation(context,webSocket, ct,
command.Parameters.ToString()); break; } } } else if (context.Request.Path.Equals
("/CheckEmailConfirmationStatus")) { await ProcessEmailConfirmation(context); } else if (context.Request.Path.Equals
("/CheckGameInvitationConfirmationStatus")) { await ProcessGameInvitationConfirmation(context); } else { await _next?.Invoke(context); } }

In this section, you have learned how to use method injection in your ASP.NET Core 3 web applications. This is the preferred method for injecting your services and you should use it whenever applicable.

You have advanced well with the implementation of the Tic-Tac-Toe game. Mostly everything around user registration, email confirmation, game invitation, and game invitation confirmation has now been implemented.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.59.81