I have an asp.net web API and I am using EF6 to connect to a third party rest API which sells online game codes. We made a deal with the company so clients have to call my rest API in order to get the game codes. Clients can list the available games via product method. Initiation is the first step of buying process. Initiation method sends JWT token in order to let client use it and finish purchase of the game code in the confirmation method. And there are reconciliation methods, recon initiation is like the initiation method just for sending back a JWT. Client uses this JWT and call recon confirmation to update a specific purchase like sold, not sold.
Is my usage correct? Would you please guide me? Dbcontext is disposed when the request completed right? And if I pass context to a method inside of another class (Utilities) to make some DB process, after completion of the process does ninject dispose the context?
Here is my sample Dbcontext:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace EPINMiddleWareAPI.Models
{
public class EPINMiddleWareAPIContext : DbContext
{
public EPINMiddleWareAPIContext() : base("name=EPINMiddleWareAPIContext")
{
}
public DbSet<InitiateRequest> InitiateRequests { get; set; }
public DbSet<InitiateResponse> InitiateResponses { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<ConfirmRequest> ConfirmRequests { get; set; }
public DbSet<ConfirmResponse> ConfirmResponses { get; set; }
public DbSet<GameBank> GameBanks { get; set; }
public DbSet<GameCouponBank> GameCouponBanks { get; set; }
}
}
Here is my ninject:
using EPINMiddleWareAPI.Controllers;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(EPINMiddleWareAPI.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(EPINMiddleWareAPI.App_Start.NinjectWebCommon), "Stop")]
namespace EPINMiddleWareAPI.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Models;
using Ninject.Web.Common.WebHost;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<EPINMiddleWareAPIContext>().ToSelf().InRequestScope();
}
}
}
And my controller:
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using EPINMiddleWareAPI.Models;
using Newtonsoft.Json;
using System.Net;
using EPINMiddleWareAPI.Utility;
using System.Linq;
using System.Data.Entity;
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using System.Collections;
using System.Linq;
namespace EPINMiddleWareAPI.Controllers
{
[System.Web.Http.RoutePrefix("api/v2/pin")]
public class InitiatesController : ApiController
{
private readonly EPINMiddleWareAPIContext context;
public InitiatesController(EPINMiddleWareAPIContext context)
{
this.context = context;
}
// POST: api/Game
//[RequireHttps] For Prod Only
[HttpPost, Route("initiation")]
public async Task<IHttpActionResult> PostInitiate(InitiateRequest initiate)
{
#region Is referenceId Unique?
if (await Utilities.IsUnique(context, initiate) > 0)
{
ModelState.AddModelError("referenceId", "This referenceId has used!");
}
#endregion
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
#region Validate Company
var responseMsg = new HttpResponseMessage();
var isUsernamePasswordValid = false;
//Find Company in our database
var companyCheck =
await (context.Companies.Where(p => p.customerID == initiate.customerID)).SingleOrDefaultAsync();
//Check company password in our database
if (companyCheck != null)
{
isUsernamePasswordValid = Utilities.VerifyPassword(initiate.password, companyCheck.hash, companyCheck.salt);
}
//Send UnAuthorized if we don't know the company
if (!isUsernamePasswordValid)
{
// if credentials are not valid send unauthorized status code in response
responseMsg.StatusCode = HttpStatusCode.Unauthorized;
IHttpActionResult rMessage = ResponseMessage(responseMsg);
return rMessage;
}
#endregion
#region Check Code Bank database
//Check Games in our database - all or nothing
var gameBankResult = await (context.GameBanks.Where(g => g.productCode == initiate.productCode)
.Where(l => l.referenceId == null)
).ToListAsync();
//If we have exact number of games in our database, mark them!
if (gameBankResult.Count() != 0 && gameBankResult.Count() >= initiate.quantity)
{
for (var index = 0; index < initiate.quantity; index++)
{
var item = gameBankResult[index];
item.referenceId = initiate.referenceId;
context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
//Update marked games
await context.SaveChangesAsync();
//Create token
var token = Utilities.createToken(companyCheck.userName);
//Return marked games in our database
var gameBankResultVM = await (context.GameBanks.Where(g => g.productCode == initiate.productCode)
.Where(l => l.referenceId == initiate.referenceId)
.Take(initiate.quantity)
.Select(g => new GameBankInitiationResponseVM()
{
referenceId = g.referenceId,
productCode = g.productCode,
quantity = initiate.quantity,
initiationResultCode = g.initiationResultCode,
validatedToken = g.validatedToken,
currency = g.currency,
estimateUnitPrice = g.estimateUnitPrice,
version = g.version,
signature = g.signature,
ApplicationCode = g.ApplicationCode,
companyToken = token,
})).ToListAsync();
var resultObj = gameBankResultVM[0];
var initiateResponse = JsonConvert.SerializeObject(resultObj);
var responseDB = JsonConvert.DeserializeObject<InitiateResponse>(initiateResponse);
//Adding Response into database
context.InitiateResponses.Add(responseDB);
await context.SaveChangesAsync();
return Ok(resultObj);
}
#endregion
// Add Signature
initiate = Utilities.CreateSignature(initiate);
#region Insert Request into DB
//Adding Request into database
context.InitiateRequests.Add(initiate);
await context.SaveChangesAsync();
#endregion
#region Call Game
var httpClient = new HttpClient();
//Convert request
var keyValues = initiate.ToKeyValue();
var content = new FormUrlEncodedContent(keyValues);
//Call Game Sultan
var response =
await httpClient.PostAsync("https://test.com/purchaseinitiation",content);
#endregion
//Read response
var htmlResponse = await response.Content.ReadAsStringAsync();
switch (response.StatusCode)
{
case HttpStatusCode.NotFound:
{
return NotFound();
}
case HttpStatusCode.InternalServerError:
{
return InternalServerError();
}
case HttpStatusCode.OK:
{
var initiateResponse = JsonConvert.DeserializeObject<InitiateResponse>(htmlResponse);
//Create Token if the result is SUCCESS
if (initiateResponse.initiationResultCode == "00")
{
//Create TOKEN and set
initiateResponse.companyToken = Utilities.createToken(companyCheck.userName);
}
//Adding Response into database
context.InitiateResponses.Add(initiateResponse);
await context.SaveChangesAsync();
return Ok(initiateResponse);
}
case HttpStatusCode.BadRequest:
{
return BadRequest(htmlResponse);
}
case HttpStatusCode.Unauthorized:
{
return Unauthorized();
}
case HttpStatusCode.RequestTimeout:
{
return InternalServerError();
}
default:
{
htmlResponse = await response.Content.ReadAsStringAsync();
break;
}
}
return Ok(htmlResponse);
}
// POST: api/Game
//[RequireHttps] For Prod Only
[Authorize]
[HttpPost, Route("confirmation")]
public async Task<IHttpActionResult> PostConfirmation(ConfirmRequest confirm)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
#region Validate Company
var responseMsg = new HttpResponseMessage();
var isUsernamePasswordValid = false;
//Find Company in our database
var companyCheck =
await (context.Companies.Where(p => p.customerID == confirm.customerID)).SingleOrDefaultAsync();
//Check company password in our database
if (companyCheck != null)
isUsernamePasswordValid = Utilities.VerifyPassword(confirm.password, companyCheck.hash, companyCheck.salt);
//Send UnAuthorized if we don't know the company
if (!isUsernamePasswordValid)
{
// if credentials are not valid send unauthorized status code in response
responseMsg.StatusCode = HttpStatusCode.Unauthorized;
IHttpActionResult rMessage = ResponseMessage(responseMsg);
return rMessage;
}
#endregion
#region Check Code Bank database
//Return marked games in our database
var gameBankResultVM = await (context.GameBanks
.Where(l => l.referenceId == confirm.referenceId)
.Select(g => new GameBankConfirmResponseVM()
{
referenceId = g.referenceId,
paymentId = null,
productCode = g.productCode,
quantity = g.quantity,
deliveredQuantity = g.quantity,
currency = g.currency,
version = g.version,
signature = g.signature,
ApplicationCode = g.ApplicationCode,
productDescription = g.productDescription,
unitPrice = g.unitPrice,
totalPrice = g.totalPrice,
totalPayablePrice = g.totalPrice,
coupons = g.coupons.Select(c => new GameCouponBankVM()
{
Pin = c.Pin,
Serial = c.Serial,
expiryDate = c.expiryDate
}).ToList()
})).ToListAsync();
//If we have games in our database, select them!
if (gameBankResultVM.Count() != 0)
{
if (gameBankResultVM.Count <= 1)
{
//Adding Response into database
var responseNew = JsonConvert.SerializeObject(gameBankResultVM[0]);
var confirmResponse = JsonConvert.DeserializeObject<ConfirmResponse>(responseNew);
context.ConfirmResponses.Add(confirmResponse);
await context.SaveChangesAsync();
return Ok(gameBankResultVM[0]);
}
else if(gameBankResultVM.Count > 1)
{
var gameResult = new GameBankConfirmResponseVM();
var price = 0.0;
var quantity = 0;
foreach (var item in gameBankResultVM)
{
price = price + item.unitPrice;
quantity = quantity + 1;
foreach (var coupons in item.coupons)
{
var gameCouponResult = new GameCouponBankVM
{
expiryDate = coupons.expiryDate,
Pin = coupons.Pin,
Serial = coupons.Serial
};
//Add coupon values
gameResult.coupons.Add(gameCouponResult);
}
}
//Set summed/counted values
gameResult.referenceId = gameBankResultVM[0].referenceId;
gameResult.paymentId = gameBankResultVM[0].paymentId;
gameResult.productCode = gameBankResultVM[0].productCode;
gameResult.quantity = quantity;
gameResult.deliveredQuantity = quantity;
gameResult.currency = gameBankResultVM[0].currency;
gameResult.unitPrice = gameBankResultVM[0].unitPrice;
gameResult.totalPrice = price;
gameResult.purchaseStatusDate = gameBankResultVM[0].purchaseStatusDate;
gameResult.productDescription = gameBankResultVM[0].productDescription;
gameResult.totalPayablePrice = price;
gameResult.version = gameBankResultVM[0].version;
gameResult.signature = null;
gameResult.ApplicationCode = null;
//Adding Response into database
var responseNew = JsonConvert.SerializeObject(gameResult);
var confirmResponse = JsonConvert.DeserializeObject<ConfirmResponse>(responseNew);
context.ConfirmResponses.Add(confirmResponse);
await context.SaveChangesAsync();
return Ok(gameResult);
}
}
#endregion
// Add Signature
confirm = Utilities.CreateSignature(confirm);
// Save Request into Table
context.ConfirmRequests.Add(confirm);
await context.SaveChangesAsync();
var httpClient = new HttpClient();
var keyValues = confirm.ToKeyValue();
var content = new FormUrlEncodedContent(keyValues);
var response =
await httpClient.PostAsync("https://test.com/purchaseconfirmation", content);
var htmlResponse = await response.Content.ReadAsStringAsync();
switch (response.StatusCode)
{
case HttpStatusCode.NotFound:
return NotFound();
case HttpStatusCode.InternalServerError:
return InternalServerError();
case HttpStatusCode.OK:
//Adding Response into database
var newResult = JObject.Parse(htmlResponse);
var confirmResponse = JsonConvert.DeserializeObject<ConfirmResponse>(newResult.ToString());
context.ConfirmResponses.Add(confirmResponse);
await context.SaveChangesAsync();
return Ok(newResult);
case HttpStatusCode.BadRequest:
return BadRequest();
case HttpStatusCode.Unauthorized:
return Unauthorized();
case HttpStatusCode.RequestTimeout:
return InternalServerError();
default:
htmlResponse = await response.Content.ReadAsStringAsync();
break;
}
return Ok(htmlResponse);
}
[HttpPatch, Route("reconInitiation")]
public async Task<IHttpActionResult> PatchReconciliationInitiation(Recon recon)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
#region Validate Company
var responseMsg = new HttpResponseMessage();
var isUsernamePasswordValid = false;
//Company password check
var companyCheck =
await (context.Companies.Where(p => p.customerID == recon.customerID)).SingleOrDefaultAsync();
if (companyCheck != null)
isUsernamePasswordValid = Utilities.VerifyPassword(recon.password, companyCheck.hash, companyCheck.salt);
if (!isUsernamePasswordValid)
{
// if credentials are not valid send unauthorized status code in response
responseMsg.StatusCode = HttpStatusCode.Unauthorized;
IHttpActionResult rMessage = ResponseMessage(responseMsg);
return rMessage;
}
#endregion
//Projection
var reconInitiateVm = new ReconInitiationVM();
//Create TOKEN and set
reconInitiateVm.companyToken = Utilities.createToken(companyCheck.userName);
return Ok(reconInitiateVm);
}
[Authorize]
[HttpPatch, Route("reconConfirmation")]
public async Task<IHttpActionResult> PatchReconciliationConfirmation(Recon recon)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
#region Validate Company
var responseMsg = new HttpResponseMessage();
var isUsernamePasswordValid = false;
//Company password check
var companyCheck =
await (context.Companies.Where(p => p.customerID == recon.customerID)).SingleOrDefaultAsync();
if (companyCheck != null)
isUsernamePasswordValid = Utilities.VerifyPassword(recon.password, companyCheck.hash, companyCheck.salt);
if (!isUsernamePasswordValid)
{
// if credentials are not valid send unauthorized status code in response
responseMsg.StatusCode = HttpStatusCode.Unauthorized;
IHttpActionResult rMessage = ResponseMessage(responseMsg);
return rMessage;
}
#endregion
#region Check Our Database
DateTime? today = DateTime.Today;
var reconResult = await (context.GameBanks.Where(g => g.used == 0)
.Where(l => l.referenceId != null)
.Where(t => System.Data.Entity.DbFunctions.TruncateTime(t.responseDateTime) == today)
).ToListAsync();
if (reconResult.Count() != 0)
{
foreach (var item in reconResult)
{
foreach (var reference in recon.referenceId)
{
if (item.referenceId == reference)
{
item.used = 1;
context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
}
}
await context.SaveChangesAsync();
}
#endregion
#region Check ConfirmResponse - Razer
var reconResultRazer = await (context.ConfirmResponses.Where(g => g.used == 0)
.Where(l => l.referenceId != null)
.Where(t => System.Data.Entity.DbFunctions.TruncateTime(t.purchaseStatusDate) == today)
).ToListAsync();
if (reconResultRazer.Count() != 0)
{
foreach (var item in reconResultRazer)
{
foreach (var reference in recon.referenceId)
{
if (item.referenceId == reference)
{
item.used = 1;
context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
}
}
await context.SaveChangesAsync();
}
#endregion
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Game
//[RequireHttps] For Prod Only
[HttpPost, Route("products")]
public async Task<IHttpActionResult> PostProducts(ProductRequest products)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
#region Validate Company
var responseMsg = new HttpResponseMessage();
var isUsernamePasswordValid = false;
//Find Company in our database
var companyCheck =
await (context.Companies.Where(p => p.customerID == products.customerID)).SingleOrDefaultAsync();
//Check company password in our database
if (companyCheck != null)
{
isUsernamePasswordValid =
Utilities.VerifyPassword(products.password, companyCheck.hash, companyCheck.salt);
}
//Send UnAuthorized if we don't know the company
if (!isUsernamePasswordValid)
{
// if credentials are not valid send unauthorized status code in response
responseMsg.StatusCode = HttpStatusCode.Unauthorized;
IHttpActionResult rMessage = ResponseMessage(responseMsg);
return rMessage;
}
#endregion
#region Check Code Bank database
//Return marked games in our database
var productsList = (context.GameBanks.AsEnumerable()
.Where(x => x.used == 0)
.GroupBy(g => new
{
g.productCode,
g.productDescription,
g.unitPrice
//g.used,
})
.Select(gcs => new
{
ProductID = Utilities.ConvertToLong(gcs.Key.productCode),
ProductName = gcs.Key.productDescription,
Price = gcs.Key.unitPrice,
//gcs.Key.used,
StockQuantity = gcs.Sum(g => g.quantity),
IsStockAvailable = Utilities.ConvertToBoolean(gcs.Sum(g => g.quantity) > 0 ? "True" : "False"),
}
)).ToList();
var list1 = productsList;
//var productResult = new ProductsResponse();
//foreach (var item in productsList)
//{
// var productDetailsResult = new Product()
// {
// ProductID = Convert.ToInt64(item),
// ProductName = item.ProductName,
// GameName = item.ProductName,
// Price = item.Price,
// StockQuantity = item.StockQuantity,
// IsStockAvailable = Convert.ToBoolean(item.IsStockAvailable),
// SmallProductImage = "No Image",
// SupplierName = "No Supplier",
// SupplierID = 1,
// GameID = 1
// };
// //Add coupon values
// productResult.Products.Add(productDetailsResult);
//}
// Add Signature
products = Utilities.CreateSignature(products);
var httpClient = new HttpClient();
var keyValues = products.ToKeyValue();
var content = new FormUrlEncodedContent(keyValues);
var response =
await httpClient.PostAsync("https://test.com/Product/", content);
var htmlResponse = await response.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<ProductsResponse>(htmlResponse);
var productsListRazer = model.Products
.Select(gcs => new
{
gcs.ProductID,
gcs.ProductName,
gcs.Price,
gcs.StockQuantity,
gcs.IsStockAvailable
}
).ToList();
var list2 = productsListRazer;
var merged = list1.Concat(list2)
.GroupBy(g => new
{
g.ProductID,
g.ProductName,
g.Price,
//g.StockQuantity,
g.IsStockAvailable
})
.Select(gcs => new
{
gcs.First().ProductID,
gcs.Key.ProductName,
gcs.Key.Price,
StockQuantity = gcs.Sum(g => g.StockQuantity),
gcs.Key.IsStockAvailable
}).ToList();
return Ok(merged);
#endregion
}
protected override void Dispose(bool disposing)
{
context.Dispose();
base.Dispose(disposing);
}
}
}