@ -0,0 +1,32 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using System.IO; | |||||
using Microsoft.AspNetCore.Hosting; | |||||
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 | |||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers | |||||
{ | |||||
[Route("api/v1/[controller]")] | |||||
public class PicController : Controller | |||||
{ | |||||
private readonly IHostingEnvironment _env; | |||||
public PicController(IHostingEnvironment env) | |||||
{ | |||||
_env = env; | |||||
} | |||||
[HttpGet("{id}")] | |||||
// GET: /<controller>/ | |||||
public IActionResult GetImage(int id) | |||||
{ | |||||
var webRoot = _env.WebRootPath; | |||||
var path = Path.Combine(webRoot, id + ".png"); | |||||
Byte[] b = System.IO.File.ReadAllBytes(path); | |||||
return File(b, "image/png"); | |||||
} | |||||
} | |||||
} |
@ -1,360 +0,0 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Microsoft.AspNetCore.Authorization; | |||||
using Microsoft.AspNetCore.Identity; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.Extensions.Logging; | |||||
using eShopOnContainers.Identity.Models; | |||||
using eShopOnContainers.Identity.Models.ManageViewModels; | |||||
using eShopOnContainers.Identity.Services; | |||||
namespace eShopOnContainers.Identity.Controllers | |||||
{ | |||||
[Authorize] | |||||
public class ManageController : Controller | |||||
{ | |||||
private readonly UserManager<ApplicationUser> _userManager; | |||||
private readonly SignInManager<ApplicationUser> _signInManager; | |||||
private readonly IEmailSender _emailSender; | |||||
private readonly ISmsSender _smsSender; | |||||
private readonly ILogger _logger; | |||||
public ManageController( | |||||
UserManager<ApplicationUser> userManager, | |||||
SignInManager<ApplicationUser> signInManager, | |||||
IEmailSender emailSender, | |||||
ISmsSender smsSender, | |||||
ILoggerFactory loggerFactory) | |||||
{ | |||||
_userManager = userManager; | |||||
_signInManager = signInManager; | |||||
_emailSender = emailSender; | |||||
_smsSender = smsSender; | |||||
_logger = loggerFactory.CreateLogger<ManageController>(); | |||||
} | |||||
// | |||||
// GET: /Manage/Index | |||||
[HttpGet] | |||||
public async Task<IActionResult> Index(ManageMessageId? message = null) | |||||
{ | |||||
ViewData["StatusMessage"] = | |||||
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." | |||||
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." | |||||
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set." | |||||
: message == ManageMessageId.Error ? "An error has occurred." | |||||
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added." | |||||
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." | |||||
: ""; | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user == null) | |||||
{ | |||||
return View("Error"); | |||||
} | |||||
var model = new IndexViewModel | |||||
{ | |||||
HasPassword = await _userManager.HasPasswordAsync(user), | |||||
PhoneNumber = await _userManager.GetPhoneNumberAsync(user), | |||||
TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user), | |||||
Logins = await _userManager.GetLoginsAsync(user), | |||||
BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user) | |||||
}; | |||||
return View(model); | |||||
} | |||||
// | |||||
// POST: /Manage/RemoveLogin | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account) | |||||
{ | |||||
ManageMessageId? message = ManageMessageId.Error; | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user != null) | |||||
{ | |||||
var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey); | |||||
if (result.Succeeded) | |||||
{ | |||||
await _signInManager.SignInAsync(user, isPersistent: false); | |||||
message = ManageMessageId.RemoveLoginSuccess; | |||||
} | |||||
} | |||||
return RedirectToAction(nameof(ManageLogins), new { Message = message }); | |||||
} | |||||
// | |||||
// GET: /Manage/AddPhoneNumber | |||||
public IActionResult AddPhoneNumber() | |||||
{ | |||||
return View(); | |||||
} | |||||
// | |||||
// POST: /Manage/AddPhoneNumber | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public async Task<IActionResult> AddPhoneNumber(AddPhoneNumberViewModel model) | |||||
{ | |||||
if (!ModelState.IsValid) | |||||
{ | |||||
return View(model); | |||||
} | |||||
// Generate the token and send it | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user == null) | |||||
{ | |||||
return View("Error"); | |||||
} | |||||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber); | |||||
await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code); | |||||
return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber }); | |||||
} | |||||
// | |||||
// POST: /Manage/EnableTwoFactorAuthentication | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public async Task<IActionResult> EnableTwoFactorAuthentication() | |||||
{ | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user != null) | |||||
{ | |||||
await _userManager.SetTwoFactorEnabledAsync(user, true); | |||||
await _signInManager.SignInAsync(user, isPersistent: false); | |||||
_logger.LogInformation(1, "User enabled two-factor authentication."); | |||||
} | |||||
return RedirectToAction(nameof(Index), "Manage"); | |||||
} | |||||
// | |||||
// POST: /Manage/DisableTwoFactorAuthentication | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public async Task<IActionResult> DisableTwoFactorAuthentication() | |||||
{ | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user != null) | |||||
{ | |||||
await _userManager.SetTwoFactorEnabledAsync(user, false); | |||||
await _signInManager.SignInAsync(user, isPersistent: false); | |||||
_logger.LogInformation(2, "User disabled two-factor authentication."); | |||||
} | |||||
return RedirectToAction(nameof(Index), "Manage"); | |||||
} | |||||
// | |||||
// GET: /Manage/VerifyPhoneNumber | |||||
[HttpGet] | |||||
public async Task<IActionResult> VerifyPhoneNumber(string phoneNumber) | |||||
{ | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user == null) | |||||
{ | |||||
return View("Error"); | |||||
} | |||||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber); | |||||
// Send an SMS to verify the phone number | |||||
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); | |||||
} | |||||
// | |||||
// POST: /Manage/VerifyPhoneNumber | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public async Task<IActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model) | |||||
{ | |||||
if (!ModelState.IsValid) | |||||
{ | |||||
return View(model); | |||||
} | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user != null) | |||||
{ | |||||
var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code); | |||||
if (result.Succeeded) | |||||
{ | |||||
await _signInManager.SignInAsync(user, isPersistent: false); | |||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess }); | |||||
} | |||||
} | |||||
// If we got this far, something failed, redisplay the form | |||||
ModelState.AddModelError(string.Empty, "Failed to verify phone number"); | |||||
return View(model); | |||||
} | |||||
// | |||||
// POST: /Manage/RemovePhoneNumber | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public async Task<IActionResult> RemovePhoneNumber() | |||||
{ | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user != null) | |||||
{ | |||||
var result = await _userManager.SetPhoneNumberAsync(user, null); | |||||
if (result.Succeeded) | |||||
{ | |||||
await _signInManager.SignInAsync(user, isPersistent: false); | |||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess }); | |||||
} | |||||
} | |||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); | |||||
} | |||||
// | |||||
// GET: /Manage/ChangePassword | |||||
[HttpGet] | |||||
public IActionResult ChangePassword() | |||||
{ | |||||
return View(); | |||||
} | |||||
// | |||||
// POST: /Manage/ChangePassword | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model) | |||||
{ | |||||
if (!ModelState.IsValid) | |||||
{ | |||||
return View(model); | |||||
} | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user != null) | |||||
{ | |||||
var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); | |||||
if (result.Succeeded) | |||||
{ | |||||
await _signInManager.SignInAsync(user, isPersistent: false); | |||||
_logger.LogInformation(3, "User changed their password successfully."); | |||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess }); | |||||
} | |||||
AddErrors(result); | |||||
return View(model); | |||||
} | |||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); | |||||
} | |||||
// | |||||
// GET: /Manage/SetPassword | |||||
[HttpGet] | |||||
public IActionResult SetPassword() | |||||
{ | |||||
return View(); | |||||
} | |||||
// | |||||
// POST: /Manage/SetPassword | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public async Task<IActionResult> SetPassword(SetPasswordViewModel model) | |||||
{ | |||||
if (!ModelState.IsValid) | |||||
{ | |||||
return View(model); | |||||
} | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user != null) | |||||
{ | |||||
var result = await _userManager.AddPasswordAsync(user, model.NewPassword); | |||||
if (result.Succeeded) | |||||
{ | |||||
await _signInManager.SignInAsync(user, isPersistent: false); | |||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess }); | |||||
} | |||||
AddErrors(result); | |||||
return View(model); | |||||
} | |||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error }); | |||||
} | |||||
//GET: /Manage/ManageLogins | |||||
[HttpGet] | |||||
public async Task<IActionResult> ManageLogins(ManageMessageId? message = null) | |||||
{ | |||||
ViewData["StatusMessage"] = | |||||
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." | |||||
: message == ManageMessageId.AddLoginSuccess ? "The external login was added." | |||||
: message == ManageMessageId.Error ? "An error has occurred." | |||||
: ""; | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user == null) | |||||
{ | |||||
return View("Error"); | |||||
} | |||||
var userLogins = await _userManager.GetLoginsAsync(user); | |||||
var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList(); | |||||
ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1; | |||||
return View(new ManageLoginsViewModel | |||||
{ | |||||
CurrentLogins = userLogins, | |||||
OtherLogins = otherLogins | |||||
}); | |||||
} | |||||
// | |||||
// POST: /Manage/LinkLogin | |||||
[HttpPost] | |||||
[ValidateAntiForgeryToken] | |||||
public IActionResult LinkLogin(string provider) | |||||
{ | |||||
// Request a redirect to the external login provider to link a login for the current user | |||||
var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); | |||||
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User)); | |||||
return Challenge(properties, provider); | |||||
} | |||||
// | |||||
// GET: /Manage/LinkLoginCallback | |||||
[HttpGet] | |||||
public async Task<ActionResult> LinkLoginCallback() | |||||
{ | |||||
var user = await GetCurrentUserAsync(); | |||||
if (user == null) | |||||
{ | |||||
return View("Error"); | |||||
} | |||||
var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user)); | |||||
if (info == null) | |||||
{ | |||||
return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error }); | |||||
} | |||||
var result = await _userManager.AddLoginAsync(user, info); | |||||
var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error; | |||||
return RedirectToAction(nameof(ManageLogins), new { Message = message }); | |||||
} | |||||
#region Helpers | |||||
private void AddErrors(IdentityResult result) | |||||
{ | |||||
foreach (var error in result.Errors) | |||||
{ | |||||
ModelState.AddModelError(string.Empty, error.Description); | |||||
} | |||||
} | |||||
public enum ManageMessageId | |||||
{ | |||||
AddPhoneSuccess, | |||||
AddLoginSuccess, | |||||
ChangePasswordSuccess, | |||||
SetTwoFactorSuccess, | |||||
SetPasswordSuccess, | |||||
RemoveLoginSuccess, | |||||
RemovePhoneSuccess, | |||||
Error | |||||
} | |||||
private Task<ApplicationUser> GetCurrentUserAsync() | |||||
{ | |||||
return _userManager.GetUserAsync(HttpContext.User); | |||||
} | |||||
#endregion | |||||
} | |||||
} |
@ -0,0 +1,12 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
namespace eShopOnContainers.Identity.Services | |||||
{ | |||||
public interface IRedirectService | |||||
{ | |||||
string ExtractRedirectUriFromReturnUrl(string url); | |||||
} | |||||
} |
@ -0,0 +1,36 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text.RegularExpressions; | |||||
using System.Threading.Tasks; | |||||
namespace eShopOnContainers.Identity.Services | |||||
{ | |||||
public class RedirectService : IRedirectService | |||||
{ | |||||
public string ExtractRedirectUriFromReturnUrl(string url) | |||||
{ | |||||
var result = ""; | |||||
var decodedUrl = System.Net.WebUtility.HtmlDecode(url); | |||||
var results = Regex.Split(decodedUrl, "redirect_uri="); | |||||
if (results.Length < 2) | |||||
return ""; | |||||
result = results[1]; | |||||
var splitKey = ""; | |||||
if (result.Contains("signin-oidc")) | |||||
splitKey = "signin-oidc"; | |||||
else | |||||
splitKey = "scope"; | |||||
results = Regex.Split(result, splitKey); | |||||
if (results.Length < 2) | |||||
return ""; | |||||
result = results[0]; | |||||
return result.Replace("%3A", ":").Replace("%2F", "/").Replace("&", ""); | |||||
} | |||||
} | |||||
} |
@ -1,118 +0,0 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Commands | |||||
{ | |||||
using Domain.Repositories; | |||||
using MediatR; | |||||
using System.Linq; | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
using Domain; | |||||
public class NewOrderRequestHandler | |||||
: IAsyncRequestHandler<NewOrderRequest, bool> | |||||
{ | |||||
private readonly IBuyerRepository _buyerRepository; | |||||
private readonly IOrderRepository _orderRepository; | |||||
public NewOrderRequestHandler(IBuyerRepository buyerRepository,IOrderRepository orderRepository) | |||||
{ | |||||
if (buyerRepository == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(buyerRepository)); | |||||
} | |||||
if (orderRepository == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(orderRepository)); | |||||
} | |||||
_buyerRepository = buyerRepository; | |||||
_orderRepository = orderRepository; | |||||
} | |||||
public async Task<bool> Handle(NewOrderRequest message) | |||||
{ | |||||
//find buyer/payment or add a new one buyer/payment | |||||
var buyer = await _buyerRepository.FindAsync(message.Buyer); | |||||
if (buyer == null) | |||||
{ | |||||
buyer = CreateBuyer(message); | |||||
} | |||||
var payment = GetExistingPaymentOrAddANewOne(buyer, message); | |||||
await _buyerRepository.UnitOfWork | |||||
.SaveChangesAsync(); | |||||
//create order for buyer and payment method | |||||
var order = CreateOrder(buyer.Id, payment.Id, 0); | |||||
order.SetAddress( new Address() | |||||
{ | |||||
City = message.City, | |||||
State = message.State, | |||||
Street = message.Street, | |||||
ZipCode = message.ZipCode | |||||
}); | |||||
foreach (var item in message.OrderItems) | |||||
{ | |||||
order.AddOrderItem(item); | |||||
} | |||||
_orderRepository.Add(order); | |||||
var result = await _orderRepository.UnitOfWork | |||||
.SaveChangesAsync(); | |||||
return result > 0; | |||||
} | |||||
Payment GetExistingPaymentOrAddANewOne(Buyer buyer, NewOrderRequest message) | |||||
{ | |||||
Payment payment = PaymentAlreadyExist(buyer, message); | |||||
if (payment == null) | |||||
{ | |||||
payment = CreatePayment(message); | |||||
buyer.Payments.Add(payment); | |||||
} | |||||
return payment; | |||||
} | |||||
Payment PaymentAlreadyExist(Domain.Buyer buyer, NewOrderRequest message) | |||||
{ | |||||
return buyer.Payments | |||||
.SingleOrDefault(p => | |||||
{ | |||||
return p.CardHolderName == message.CardHolderName | |||||
&& | |||||
p.CardNumber == message.CardNumber | |||||
&& | |||||
p.Expiration == message.CardExpiration | |||||
&& | |||||
p.SecurityNumber == message.CardSecurityNumber; | |||||
}); | |||||
} | |||||
Buyer CreateBuyer(NewOrderRequest message) | |||||
{ | |||||
return _buyerRepository.Add( | |||||
new Buyer(message.Buyer)); | |||||
} | |||||
Order CreateOrder(int buyerId, int paymentId, int addressId) | |||||
{ | |||||
return new Order(buyerId, paymentId); | |||||
} | |||||
Payment CreatePayment(NewOrderRequest message) | |||||
{ | |||||
return new Payment(message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration, message.CardTypeId); | |||||
} | |||||
} | |||||
} |
@ -1,48 +0,0 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Commands | |||||
{ | |||||
using System; | |||||
using MediatR; | |||||
using Domain; | |||||
using System.Collections; | |||||
using System.Collections.Generic; | |||||
public class NewOrderRequest | |||||
:IAsyncRequest<bool> | |||||
{ | |||||
private readonly List<OrderItem> _orderItems; | |||||
public string City { get; set; } | |||||
public string Street { get; set; } | |||||
public string State { get; set; } | |||||
public string Country { get; set; } | |||||
public string ZipCode { get; set; } | |||||
public string CardNumber { get; set; } | |||||
public string CardHolderName { get; set; } | |||||
public DateTime CardExpiration { get; set; } | |||||
public string CardSecurityNumber { get; set; } | |||||
public int CardTypeId { get; set; } | |||||
public string Buyer { get; set; } | |||||
public IEnumerable<OrderItem> OrderItems => _orderItems; | |||||
public void AddOrderItem(OrderItem item) | |||||
{ | |||||
_orderItems.Add(item); | |||||
} | |||||
public NewOrderRequest() | |||||
{ | |||||
_orderItems = new List<OrderItem>(); | |||||
} | |||||
} | |||||
} |
@ -1,34 +0,0 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Decorators | |||||
{ | |||||
using Extensions.Logging; | |||||
using MediatR; | |||||
using System.Threading.Tasks; | |||||
public class LogDecorator<TRequest, TResponse> | |||||
: IAsyncRequestHandler<TRequest, TResponse> | |||||
where TRequest : IAsyncRequest<TResponse> | |||||
{ | |||||
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner; | |||||
private readonly ILogger<LogDecorator<TRequest, TResponse>> _logger; | |||||
public LogDecorator( | |||||
IAsyncRequestHandler<TRequest, TResponse> inner, | |||||
ILogger<LogDecorator<TRequest, TResponse>> logger) | |||||
{ | |||||
_inner = inner; | |||||
_logger = logger; | |||||
} | |||||
public async Task<TResponse> Handle(TRequest message) | |||||
{ | |||||
_logger.LogInformation($"Executing command {_inner.GetType().FullName}"); | |||||
var response = await _inner.Handle(message); | |||||
_logger.LogInformation($"Succedded executed command {_inner.GetType().FullName}"); | |||||
return response; | |||||
} | |||||
} | |||||
} |
@ -1,19 +0,0 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||||
</PropertyGroup> | |||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||||
<PropertyGroup Label="Globals"> | |||||
<ProjectGuid>4193caa3-a1c3-4818-a06f-a2d85fde77e7</ProjectGuid> | |||||
<RootNamespace>Microsoft.eShopOnContainers.Services.Ordering.Application</RootNamespace> | |||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath> | |||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> | |||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion> | |||||
</PropertyGroup> | |||||
<PropertyGroup> | |||||
<SchemaVersion>2.0</SchemaVersion> | |||||
</PropertyGroup> | |||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> | |||||
</Project> |
@ -1,19 +0,0 @@ | |||||
using System.Reflection; | |||||
using System.Runtime.CompilerServices; | |||||
using System.Runtime.InteropServices; | |||||
// General Information about an assembly is controlled through the following | |||||
// set of attributes. Change these attribute values to modify the information | |||||
// associated with an assembly. | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("Ordering.Application")] | |||||
[assembly: AssemblyTrademark("")] | |||||
// Setting ComVisible to false makes the types in this assembly not visible | |||||
// to COM components. If you need to access a type in this assembly from | |||||
// COM, set the ComVisible attribute to true on that type. | |||||
[assembly: ComVisible(false)] | |||||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||||
[assembly: Guid("4193caa3-a1c3-4818-a06f-a2d85fde77e7")] |
@ -1,13 +0,0 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Queries | |||||
{ | |||||
using System.Threading.Tasks; | |||||
public interface IOrderQueries | |||||
{ | |||||
Task<dynamic> GetOrder(int id); | |||||
Task<dynamic> GetOrders(); | |||||
Task<dynamic> GetCardTypes(); | |||||
} | |||||
} |
@ -1,128 +0,0 @@ | |||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Queries | |||||
{ | |||||
using Dapper; | |||||
using Microsoft.Extensions.Configuration; | |||||
using System.Data.SqlClient; | |||||
using System.Threading.Tasks; | |||||
using System; | |||||
using System.Dynamic; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
public class OrderQueries | |||||
: IOrderQueries | |||||
{ | |||||
private string _connectionString = string.Empty; | |||||
public OrderQueries(IConfiguration configuration) | |||||
{ | |||||
_connectionString = configuration["ConnectionString"]; | |||||
} | |||||
public async Task<dynamic> GetOrder(int id) | |||||
{ | |||||
using (var connection = new SqlConnection(_connectionString)) | |||||
{ | |||||
connection.Open(); | |||||
var result = await connection.QueryAsync<dynamic>( | |||||
@"select o.[Id] as ordernumber,o.OrderDate as date, os.Name as status, | |||||
oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl, | |||||
oa.Street as street, oa.City as city, oa.Country as country, oa.State as state, oa.ZipCode as zipcode | |||||
FROM ordering.Orders o | |||||
LEFT JOIN ordering.Orderitems oi ON o.Id = oi.orderid | |||||
LEFT JOIN ordering.orderstatus os on o.StatusId = os.Id | |||||
LEFT JOIN ordering.address oa on o.ShippingAddressId = oa.Id | |||||
WHERE o.Id=@id" | |||||
, new { id } | |||||
); | |||||
if (result.AsList().Count == 0) | |||||
throw new KeyNotFoundException(); | |||||
return MapOrderItems(result); | |||||
} | |||||
} | |||||
public async Task<dynamic> GetOrders() | |||||
{ | |||||
using (var connection = new SqlConnection(_connectionString)) | |||||
{ | |||||
connection.Open(); | |||||
return await connection.QueryAsync<dynamic>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status],SUM(oi.units*oi.unitprice) as total | |||||
FROM [ordering].[Orders] o | |||||
LEFT JOIN[ordering].[orderitems] oi ON o.Id = oi.orderid | |||||
LEFT JOIN[ordering].[orderstatus] os on o.StatusId = os.Id | |||||
GROUP BY o.[Id], o.[OrderDate], os.[Name]"); | |||||
} | |||||
} | |||||
public async Task<dynamic> GetCardTypes() | |||||
{ | |||||
using (var connection = new SqlConnection(_connectionString)) | |||||
{ | |||||
connection.Open(); | |||||
return await connection.QueryAsync<dynamic>("SELECT * FROM ordering.cardtypes"); | |||||
} | |||||
} | |||||
private dynamic MapOrderItems(dynamic result) | |||||
{ | |||||
dynamic order = new ExpandoObject(); | |||||
order.ordernumber = result[0].ordernumber; | |||||
order.date = result[0].date; | |||||
order.status = result[0].status; | |||||
order.street = result[0].street; | |||||
order.city = result[0].city; | |||||
order.zipcode = result[0].zipcode; | |||||
order.country = result[0].country; | |||||
order.orderitems = new List<dynamic>(); | |||||
order.total = 0; | |||||
foreach (dynamic item in result) | |||||
{ | |||||
dynamic orderitem = new ExpandoObject(); | |||||
orderitem.productname = item.productname; | |||||
orderitem.units = item.units; | |||||
orderitem.unitprice = item.unitprice; | |||||
orderitem.pictureurl = item.pictureurl; | |||||
order.total += item.units * item.unitprice; | |||||
order.orderitems.Add(orderitem); | |||||
} | |||||
return order; | |||||
} | |||||
//TODO/CCE: try to use this method instead actual. | |||||
//private object MapOrderItems(dynamic result) | |||||
//{ | |||||
// IEnumerable<dynamic> items = (result as System.Collections.IEnumerable).Cast<dynamic>(); | |||||
// var order = new | |||||
// { | |||||
// ordernumber = result[0].ordernumbe, | |||||
// date = result[0].date, | |||||
// status = result[0].status, | |||||
// street = result[0].street, | |||||
// city = result[0].city, | |||||
// zipcode = result[0].zipcode, | |||||
// country = result[0].country, | |||||
// total = items.Select(r => (int)r.units * (int)r.unitprice).Sum(), | |||||
// orderItems = items.Select(r => new | |||||
// { | |||||
// productname = r.productname, | |||||
// units = r.units, | |||||
// unitprice = r.unitprice, | |||||
// pictureurl = r.pictureurl | |||||
// }) | |||||
// }; | |||||
// return order; | |||||
//} | |||||
} | |||||
} |
@ -1,21 +0,0 @@ | |||||
{ | |||||
"version": "1.0.0-*", | |||||
"dependencies": { | |||||
"NETStandard.Library": "1.6.0", | |||||
"MediatR": "2.1.0", | |||||
"Dapper": "1.50.2", | |||||
"System.Dynamic.Runtime": "4.0.11", | |||||
"Microsoft.CSharp": "4.0.1", | |||||
"Microsoft.Extensions.Configuration": "1.0.0", | |||||
"System.Data.SqlClient": "4.1.0", | |||||
"Microsoft.Extensions.Logging.Abstractions": "1.0.0", | |||||
"Ordering.Domain": "1.0.0-*" | |||||
}, | |||||
"frameworks": { | |||||
"netstandard1.6": { | |||||
"imports": "dnxcore50" | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,63 @@ | |||||
| |||||
//namespace FunctionalTests.Services.Basket | |||||
//{ | |||||
// using Microsoft.eShopOnContainers.Services.Basket.API; | |||||
// using Microsoft.eShopOnContainers.Services.Basket.API.Model; | |||||
// using Microsoft.Extensions.Logging; | |||||
// using Microsoft.Extensions.Options; | |||||
// using System.Collections.Generic; | |||||
// using System.Threading.Tasks; | |||||
// using Xunit; | |||||
// public class RedisBasketRepositoryTests | |||||
// { | |||||
// [Fact] | |||||
// public async Task UpdateBasket_return_and_add_basket() | |||||
// { | |||||
// var redisBasketRepository = BuildBasketRepository(); | |||||
// var basket = await redisBasketRepository.UpdateBasket(new CustomerBasket("customerId") | |||||
// { | |||||
// BuyerId = "buyerId", | |||||
// Items = BuildBasketItems() | |||||
// }); | |||||
// Assert.NotNull(basket); | |||||
// Assert.Equal(1, basket.Items.Count); | |||||
// } | |||||
// [Fact] | |||||
// public async Task GetBasket_return_existing_basket() | |||||
// { | |||||
// } | |||||
// RedisBasketRepository BuildBasketRepository() | |||||
// { | |||||
// var loggerFactory = new LoggerFactory(); | |||||
// var options = Options.Create<BasketSettings>(new BasketSettings() | |||||
// { | |||||
// ConnectionString = "127.0.0.1" | |||||
// }); | |||||
// return new RedisBasketRepository(options, loggerFactory); | |||||
// } | |||||
// List<BasketItem> BuildBasketItems() | |||||
// { | |||||
// return new List<BasketItem>() | |||||
// { | |||||
// new BasketItem() | |||||
// { | |||||
// Id = "basketId", | |||||
// PictureUrl = "pictureurl", | |||||
// ProductId = "productId", | |||||
// ProductName = "productName", | |||||
// Quantity = 1, | |||||
// UnitPrice = 1 | |||||
// } | |||||
// }; | |||||
// } | |||||
// } | |||||
//} |
@ -1,136 +0,0 @@ | |||||
using System; | |||||
using Xunit; | |||||
using System.Threading.Tasks; | |||||
using Moq; | |||||
using MediatR; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Commands; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services; | |||||
using Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Queries; | |||||
using System.Collections.Generic; | |||||
namespace UnitTest.Ordering.Controllers | |||||
{ | |||||
public class OrderControllerTest | |||||
{ | |||||
private readonly Mock<IMediator> _mediatorMock; | |||||
private readonly Mock<IIdentityService> _identityMock; | |||||
private readonly Mock<IOrderQueries> _queriesMock; | |||||
private readonly string _userIdentity; | |||||
public OrderControllerTest() | |||||
{ | |||||
//Mocks; | |||||
_mediatorMock = new Mock<IMediator>(); | |||||
_identityMock = new Mock<IIdentityService>(); | |||||
_queriesMock = new Mock<IOrderQueries>(); | |||||
_userIdentity = Guid.NewGuid().ToString(); | |||||
} | |||||
[Fact] | |||||
public async Task AddOrder_ReturnsBadRequestResult_WhenPersitenceOperationFails() | |||||
{ | |||||
// Arrange | |||||
var orderRequest = new object() as IAsyncRequest<bool>; | |||||
_mediatorMock.Setup(mediator => mediator.SendAsync(OrderFakeNotExpired())) | |||||
.Returns(Task.FromResult(false)); | |||||
_identityMock.Setup(identity => identity.GetUserIdentity()) | |||||
.Returns(Guid.NewGuid().ToString()); | |||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||||
// Act | |||||
var badRequestResult = await controller.AddOrder(OrderFakeNotExpired()); | |||||
// Assert | |||||
Assert.IsType<BadRequestResult>(badRequestResult); | |||||
} | |||||
[Fact] | |||||
public async Task GetOrder_ReturnsNotFound_WhenItemNotFound() | |||||
{ | |||||
// Arrange | |||||
_queriesMock.Setup(queries => queries.GetOrder(1)) | |||||
.Throws(new KeyNotFoundException()); | |||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||||
// Act | |||||
var notFoundResult = await controller.GetOrder(1); | |||||
// Assert | |||||
Assert.IsType<NotFoundResult>(notFoundResult); | |||||
} | |||||
[Fact] | |||||
public async Task GetOrder_ReturnsOkObjecResult_WheItemFound() | |||||
{ | |||||
// Arrange | |||||
_queriesMock.Setup(queries => queries.GetOrder(1)) | |||||
.Returns(Task.FromResult(new object())); | |||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||||
// Act | |||||
var OkObjectResult = await controller.GetOrder(1); | |||||
// Assert | |||||
Assert.IsType<OkObjectResult>(OkObjectResult); | |||||
} | |||||
[Fact] | |||||
public async Task GetOrders_ReturnsOkObjectResult() | |||||
{ | |||||
// Arrange | |||||
_queriesMock.Setup(queries => queries.GetOrders()) | |||||
.Returns(Task.FromResult(new object())); | |||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||||
// Act | |||||
var OkObjectResult = await controller.GetOrders(); | |||||
// Assert | |||||
Assert.IsType<OkObjectResult>(OkObjectResult); | |||||
} | |||||
[Fact] | |||||
public async Task GetCardTypes() | |||||
{ | |||||
// Arrange | |||||
_queriesMock.Setup(queries => queries.GetCardTypes()) | |||||
.Returns(Task.FromResult(new object())); | |||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object); | |||||
// Act | |||||
var OkObjectResult = await controller.GetCardTypes(); | |||||
// Assert | |||||
Assert.IsType<OkObjectResult>(OkObjectResult); | |||||
} | |||||
//Fakes | |||||
private NewOrderRequest OrderFakeNotExpired() | |||||
{ | |||||
return new NewOrderRequest() | |||||
{ | |||||
CardTypeId = 1, | |||||
CardExpiration = new DateTime(2020, 12, 12), | |||||
Buyer = _userIdentity | |||||
}; | |||||
} | |||||
private NewOrderRequest OrderFakeExpired() | |||||
{ | |||||
return new NewOrderRequest() | |||||
{ | |||||
CardTypeId = 1, | |||||
CardExpiration = DateTime.Now.AddYears(-1) | |||||
}; | |||||
} | |||||
} | |||||
} |
@ -1,50 +0,0 @@ | |||||
using System; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Xunit; | |||||
using System.Threading.Tasks; | |||||
using Moq; | |||||
using MediatR; | |||||
namespace UnitTests | |||||
{ | |||||
public class OrderControllerTest | |||||
{ | |||||
private readonly Mock<IMediator> _mock; | |||||
public OrderControllerTest() | |||||
{ | |||||
//config mock; | |||||
_mock = new Mock<IMediator>(); | |||||
} | |||||
[Fact] | |||||
public async Task AddOrder_ReturnsBadRequestResult_WhenPersitenceOperationFails() | |||||
{ | |||||
//Add order: | |||||
var orderRequest = new object() as IAsyncRequest<bool>; | |||||
_mock.Setup(mediator => mediator.SendAsync(orderRequest)) | |||||
.Returns(Task.FromResult(false)); | |||||
// Arrange | |||||
var controller = new OrdersController(mockRepo.Object); | |||||
controller.ModelState.AddModelError("SessionName", "Required"); | |||||
var newSession = new HomeController.NewSessionModel(); | |||||
// Act | |||||
var result = await controller.Index(newSession); | |||||
// Assert | |||||
var badRequestResult = Assert.IsType<BadRequestObjectResult>(result); | |||||
Assert.IsType<SerializableError>(badRequestResult.Value); | |||||
} | |||||
// Implement Fake method for mock. | |||||
private MediatorMockForAddOrder() | |||||
{ | |||||
} | |||||
} | |||||
} |
@ -1,36 +0,0 @@ | |||||
using System.Reflection; | |||||
using System.Runtime.CompilerServices; | |||||
using System.Runtime.InteropServices; | |||||
// General Information about an assembly is controlled through the following | |||||
// set of attributes. Change these attribute values to modify the information | |||||
// associated with an assembly. | |||||
[assembly: AssemblyTitle("UnitTests")] | |||||
[assembly: AssemblyDescription("")] | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("UnitTests")] | |||||
[assembly: AssemblyCopyright("Copyright © 2016")] | |||||
[assembly: AssemblyTrademark("")] | |||||
[assembly: AssemblyCulture("")] | |||||
// Setting ComVisible to false makes the types in this assembly not visible | |||||
// to COM components. If you need to access a type in this assembly from | |||||
// COM, set the ComVisible attribute to true on that type. | |||||
[assembly: ComVisible(false)] | |||||
// The following GUID is for the ID of the typelib if this project is exposed to COM | |||||
[assembly: Guid("ecbb8dc1-22ea-42d2-a45a-4ae800c73356")] | |||||
// Version information for an assembly consists of the following four values: | |||||
// | |||||
// Major Version | |||||
// Minor Version | |||||
// Build Number | |||||
// Revision | |||||
// | |||||
// You can specify all the values or you can default the Build and Revision Numbers | |||||
// by using the '*' as shown below: | |||||
// [assembly: AssemblyVersion("1.0.*")] | |||||
[assembly: AssemblyVersion("1.0.0.0")] | |||||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@ -1,117 +0,0 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||||
<ProjectGuid>{ECBB8DC1-22EA-42D2-A45A-4AE800C73356}</ProjectGuid> | |||||
<OutputType>Library</OutputType> | |||||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||||
<RootNamespace>UnitTests</RootNamespace> | |||||
<AssemblyName>UnitTests</AssemblyName> | |||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> | |||||
<FileAlignment>512</FileAlignment> | |||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> | |||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> | |||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath> | |||||
<IsCodedUITest>False</IsCodedUITest> | |||||
<TestProjectType>UnitTest</TestProjectType> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DebugType>full</DebugType> | |||||
<Optimize>false</Optimize> | |||||
<OutputPath>bin\Debug\</OutputPath> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||||
<DebugType>pdbonly</DebugType> | |||||
<Optimize>true</Optimize> | |||||
<OutputPath>bin\Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL"> | |||||
<HintPath>..\..\..\..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath> | |||||
<Private>True</Private> | |||||
</Reference> | |||||
<Reference Include="MediatR, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL"> | |||||
<HintPath>..\..\..\..\packages\MediatR.2.1.0\lib\net45\MediatR.dll</HintPath> | |||||
<Private>True</Private> | |||||
</Reference> | |||||
<Reference Include="Moq, Version=4.6.38.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL"> | |||||
<HintPath>..\..\..\..\packages\Moq.4.6.38-alpha\lib\net45\Moq.dll</HintPath> | |||||
<Private>True</Private> | |||||
</Reference> | |||||
<Reference Include="System" /> | |||||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||||
<HintPath>..\..\..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath> | |||||
<Private>True</Private> | |||||
</Reference> | |||||
<Reference Include="xunit.assert, Version=2.2.0.3444, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||||
<HintPath>..\..\..\..\packages\xunit.assert.2.2.0-beta4-build3444\lib\netstandard1.0\xunit.assert.dll</HintPath> | |||||
<Private>True</Private> | |||||
</Reference> | |||||
<Reference Include="xunit.core, Version=2.2.0.3444, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||||
<HintPath>..\..\..\..\packages\xunit.extensibility.core.2.2.0-beta4-build3444\lib\net45\xunit.core.dll</HintPath> | |||||
<Private>True</Private> | |||||
</Reference> | |||||
<Reference Include="xunit.execution.desktop, Version=2.2.0.3444, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL"> | |||||
<HintPath>..\..\..\..\packages\xunit.extensibility.execution.2.2.0-beta4-build3444\lib\net45\xunit.execution.desktop.dll</HintPath> | |||||
<Private>True</Private> | |||||
</Reference> | |||||
</ItemGroup> | |||||
<Choose> | |||||
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'"> | |||||
<ItemGroup> | |||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> | |||||
</ItemGroup> | |||||
</When> | |||||
<Otherwise> | |||||
<ItemGroup> | |||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" /> | |||||
</ItemGroup> | |||||
</Otherwise> | |||||
</Choose> | |||||
<ItemGroup> | |||||
<Compile Include="Ordering\OrderControllerTest.cs" /> | |||||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Folder Include="Catalog\" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="packages.config" /> | |||||
</ItemGroup> | |||||
<Choose> | |||||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'"> | |||||
<ItemGroup> | |||||
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||||
<Private>False</Private> | |||||
</Reference> | |||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||||
<Private>False</Private> | |||||
</Reference> | |||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||||
<Private>False</Private> | |||||
</Reference> | |||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> | |||||
<Private>False</Private> | |||||
</Reference> | |||||
</ItemGroup> | |||||
</When> | |||||
</Choose> | |||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||||
Other similar extension points exist, see Microsoft.Common.targets. | |||||
<Target Name="BeforeBuild"> | |||||
</Target> | |||||
<Target Name="AfterBuild"> | |||||
</Target> | |||||
--> | |||||
</Project> |
@ -1,12 +0,0 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<packages> | |||||
<package id="Castle.Core" version="3.3.3" targetFramework="net452" /> | |||||
<package id="MediatR" version="2.1.0" targetFramework="net452" /> | |||||
<package id="Moq" version="4.6.38-alpha" targetFramework="net452" /> | |||||
<package id="xunit" version="2.2.0-beta4-build3444" targetFramework="net452" /> | |||||
<package id="xunit.abstractions" version="2.0.1" targetFramework="net452" /> | |||||
<package id="xunit.assert" version="2.2.0-beta4-build3444" targetFramework="net452" /> | |||||
<package id="xunit.core" version="2.2.0-beta4-build3444" targetFramework="net452" /> | |||||
<package id="xunit.extensibility.core" version="2.2.0-beta4-build3444" targetFramework="net452" /> | |||||
<package id="xunit.extensibility.execution" version="2.2.0-beta4-build3444" targetFramework="net452" /> | |||||
</packages> |