Merge branch 'dev' of https://github.com/dotnet/eShopOnContainers into dev
This commit is contained in:
commit
a8733ac271
@ -130,20 +130,21 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
return Ok(items);
|
||||
}
|
||||
|
||||
[Route("edit")]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Post([FromBody]CatalogItem value)
|
||||
public async Task<IActionResult> EditProduct([FromBody]CatalogItem product)
|
||||
{
|
||||
var item = await _context.CatalogItems.SingleOrDefaultAsync(i => i.Id == value.Id);
|
||||
var item = await _context.CatalogItems.SingleOrDefaultAsync(i => i.Id == product.Id);
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (item.Price != value.Price)
|
||||
if (item.Price != product.Price)
|
||||
{
|
||||
var oldPrice = item.Price;
|
||||
item.Price = value.Price;
|
||||
item.Price = product.Price;
|
||||
_context.CatalogItems.Update(item);
|
||||
|
||||
var @event = new ProductPriceChangedIntegrationEvent(item.Id, item.Price, oldPrice);
|
||||
@ -158,10 +159,47 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
eventLogEntry.State = EventStateEnum.Published;
|
||||
_context.IntegrationEventLog.Update(eventLogEntry);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
[Route("create")]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateProduct([FromBody]CatalogItem product)
|
||||
{
|
||||
_context.CatalogItems.Add(
|
||||
new CatalogItem
|
||||
{
|
||||
CatalogBrandId = product.CatalogBrandId,
|
||||
CatalogTypeId = product.CatalogTypeId,
|
||||
Description = product.Description,
|
||||
Name = product.Name,
|
||||
PictureUri = product.PictureUri,
|
||||
Price = product.Price
|
||||
});
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[Route("{id}")]
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> DeleteProduct(int id)
|
||||
{
|
||||
var product = _context.CatalogItems.SingleOrDefault(x => x.Id == id);
|
||||
|
||||
if (product == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_context.CatalogItems.Remove(product);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
private List<CatalogItem> ComposePicUri(List<CatalogItem> items) {
|
||||
var baseUri = _settings.Value.ExternalCatalogBaseUrl;
|
||||
|
@ -11,16 +11,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||
public class AccountController : Controller
|
||||
{
|
||||
private readonly IIdentityParser<ApplicationUser> _identityParser;
|
||||
public AccountController(IIdentityParser<ApplicationUser> identityParser)
|
||||
{
|
||||
public AccountController(IIdentityParser<ApplicationUser> identityParser) =>
|
||||
_identityParser = identityParser;
|
||||
}
|
||||
|
||||
public ActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public ActionResult Index() => View();
|
||||
|
||||
[Authorize]
|
||||
public IActionResult SignIn(string returnUrl)
|
||||
{
|
||||
|
@ -14,10 +14,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||
{
|
||||
private ICatalogService _catalogSvc;
|
||||
|
||||
public CatalogController(ICatalogService catalogSvc)
|
||||
{
|
||||
public CatalogController(ICatalogService catalogSvc) =>
|
||||
_catalogSvc = catalogSvc;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index(int? BrandFilterApplied, int? TypesFilterApplied, int? page)
|
||||
{
|
||||
@ -35,7 +33,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||
ActualPage = page ?? 0,
|
||||
ItemsPerPage = catalog.Data.Count,
|
||||
TotalItems = catalog.Count,
|
||||
TotalPages = int.Parse(Math.Ceiling(((decimal)catalog.Count / itemsPage)).ToString())
|
||||
TotalPages = (int)Math.Ceiling(((decimal)catalog.Count / itemsPage))
|
||||
}
|
||||
};
|
||||
|
||||
@ -45,10 +43,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
public IActionResult Error() => View();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,20 +11,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Extensions
|
||||
{
|
||||
public static class HttpClientExtensions
|
||||
{
|
||||
public static void SetBasicAuthentication(this HttpClient client, string userName, string password)
|
||||
{
|
||||
public static void SetBasicAuthentication(this HttpClient client, string userName, string password) =>
|
||||
client.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue(userName, password);
|
||||
}
|
||||
|
||||
public static void SetToken(this HttpClient client, string scheme, string token)
|
||||
{
|
||||
public static void SetToken(this HttpClient client, string scheme, string token) =>
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(scheme, token);
|
||||
}
|
||||
|
||||
public static void SetBearerToken(this HttpClient client, string token)
|
||||
{
|
||||
public static void SetBearerToken(this HttpClient client, string token) =>
|
||||
client.SetToken(JwtConstants.TokenType, token);
|
||||
}
|
||||
}
|
||||
|
||||
public class BasicAuthenticationHeaderValue : AuthenticationHeaderValue
|
||||
|
@ -8,10 +8,8 @@ using System.Threading.Tasks;
|
||||
|
||||
public static class SessionExtensions
|
||||
{
|
||||
public static void SetObject(this ISession session, string key, object value)
|
||||
{
|
||||
public static void SetObject(this ISession session, string key, object value) =>
|
||||
session.SetString(key, JsonConvert.SerializeObject(value));
|
||||
}
|
||||
|
||||
public static T GetObject<T>(this ISession session, string key)
|
||||
{
|
||||
|
@ -33,16 +33,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
|
||||
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||
|
||||
var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id.ToString()}";
|
||||
var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id}";
|
||||
var dataString = await _apiClient.GetStringAsync(basketUrl);
|
||||
var response = JsonConvert.DeserializeObject<Basket>(dataString);
|
||||
if (response == null)
|
||||
{
|
||||
response = new Basket()
|
||||
// Use the ?? Null conditional operator to simplify the initialization of response
|
||||
var response = JsonConvert.DeserializeObject<Basket>(dataString) ??
|
||||
new Basket()
|
||||
{
|
||||
BuyerId = user.Id
|
||||
};
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
@ -67,9 +65,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
|
||||
basket.Items.ForEach(x =>
|
||||
{
|
||||
var quantity = quantities.Where(y => y.Key == x.Id).FirstOrDefault();
|
||||
if (quantities.Where(y => y.Key == x.Id).Count() > 0)
|
||||
x.Quantity = quantity.Value;
|
||||
// Simplify this logic by using the
|
||||
// new out variable initializer.
|
||||
if (quantities.TryGetValue(x.Id, out var quantity))
|
||||
{
|
||||
x.Quantity = quantity;
|
||||
}
|
||||
});
|
||||
|
||||
return basket;
|
||||
@ -119,7 +120,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
var token = await context.Authentication.GetTokenAsync("access_token");
|
||||
|
||||
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||
var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id.ToString()}";
|
||||
var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id}";
|
||||
var response = await _apiClient.DeleteAsync(basketUrl);
|
||||
|
||||
//CCE: response status code...
|
||||
|
@ -61,8 +61,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
JArray brands = JArray.Parse(dataString);
|
||||
foreach (JObject brand in brands.Children<JObject>())
|
||||
{
|
||||
dynamic item = brand;
|
||||
items.Add(new SelectListItem() { Value = item.id, Text = item.brand });
|
||||
items.Add(new SelectListItem()
|
||||
{
|
||||
Value = brand.Value<string>("id"),
|
||||
Text = brand.Value<string>("brand")
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
@ -79,10 +82,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
JArray brands = JArray.Parse(dataString);
|
||||
foreach (JObject brand in brands.Children<JObject>())
|
||||
{
|
||||
dynamic item = brand;
|
||||
items.Add(new SelectListItem() { Value = item.id, Text = item.type });
|
||||
items.Add(new SelectListItem()
|
||||
{
|
||||
Value = brand.Value<string>("id"),
|
||||
Text = brand.Value<string>("type")
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
@ -12,26 +12,31 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
||||
{
|
||||
public ApplicationUser Parse(IPrincipal principal)
|
||||
{
|
||||
var user = new ApplicationUser();
|
||||
var claims = (ClaimsPrincipal)principal;
|
||||
// Pattern matching 'is' expression
|
||||
// assigns "claims" if "principal" is a "ClaimsPrincipal"
|
||||
if (principal is ClaimsPrincipal claims)
|
||||
{
|
||||
return new ApplicationUser
|
||||
{
|
||||
|
||||
user.CardHolderName = (claims.Claims.Where(x => x.Type == "card_holder").Count() > 0) ? claims.Claims.First(x => x.Type == "card_holder").Value : "";
|
||||
user.CardNumber = (claims.Claims.Where(x => x.Type == "card_number").Count() > 0) ? claims.Claims.First(x => x.Type == "card_number").Value : "";
|
||||
user.Expiration = (claims.Claims.Where(x => x.Type == "card_expiration").Count() > 0) ? claims.Claims.First(x => x.Type == "card_expiration").Value : "";
|
||||
user.CardType = (claims.Claims.Where(x => x.Type == "missing").Count() > 0) ? int.Parse(claims.Claims.First(x => x.Type == "missing").Value) : 0;
|
||||
user.City = (claims.Claims.Where(x => x.Type == "address_city").Count() > 0) ? claims.Claims.First(x => x.Type == "address_city").Value : "";
|
||||
user.Country = (claims.Claims.Where(x => x.Type == "address_country").Count() > 0) ? claims.Claims.First(x => x.Type == "address_country").Value : "";
|
||||
user.Email = (claims.Claims.Where(x => x.Type == "email").Count() > 0) ? claims.Claims.First(x => x.Type == "email").Value : "";
|
||||
user.Id = (claims.Claims.Where(x => x.Type == "sub").Count() > 0) ? claims.Claims.First(x => x.Type == "sub").Value : "";
|
||||
user.LastName = (claims.Claims.Where(x => x.Type == "last_name").Count() > 0) ? claims.Claims.First(x => x.Type == "last_name").Value : "";
|
||||
user.Name = (claims.Claims.Where(x => x.Type == "name").Count() > 0) ? claims.Claims.First(x => x.Type == "name").Value : "";
|
||||
user.PhoneNumber = (claims.Claims.Where(x => x.Type == "phone_number").Count() > 0) ? claims.Claims.First(x => x.Type == "phone_number").Value : "";
|
||||
user.SecurityNumber = (claims.Claims.Where(x => x.Type == "card_security_number").Count() > 0) ? claims.Claims.First(x => x.Type == "card_security_number").Value : "";
|
||||
user.State = (claims.Claims.Where(x => x.Type == "address_state").Count() > 0) ? claims.Claims.First(x => x.Type == "address_state").Value : "";
|
||||
user.Street = (claims.Claims.Where(x => x.Type == "address_street").Count() > 0) ? claims.Claims.First(x => x.Type == "address_street").Value : "";
|
||||
user.ZipCode = (claims.Claims.Where(x => x.Type == "address_zip_code").Count() > 0) ? claims.Claims.First(x => x.Type == "address_zip_code").Value : "";
|
||||
|
||||
return user;
|
||||
CardHolderName = claims.Claims.FirstOrDefault(x => x.Type == "card_holder")?.Value ?? "",
|
||||
CardNumber = claims.Claims.FirstOrDefault(x => x.Type == "card_number")?.Value ?? "",
|
||||
Expiration = claims.Claims.FirstOrDefault(x => x.Type == "card_expiration")?.Value ?? "",
|
||||
CardType = int.Parse(claims.Claims.FirstOrDefault(x => x.Type == "missing")?.Value ?? "0"),
|
||||
City = claims.Claims.FirstOrDefault(x => x.Type == "address_city")?.Value ?? "",
|
||||
Country = claims.Claims.FirstOrDefault(x => x.Type == "address_country")?.Value ?? "",
|
||||
Email = claims.Claims.FirstOrDefault(x => x.Type == "email")?.Value ?? "",
|
||||
Id = claims.Claims.FirstOrDefault(x => x.Type == "sub")?.Value ?? "",
|
||||
LastName = claims.Claims.FirstOrDefault(x => x.Type == "last_name")?.Value ?? "",
|
||||
Name = claims.Claims.FirstOrDefault(x => x.Type == "name")?.Value ?? "",
|
||||
PhoneNumber = claims.Claims.FirstOrDefault(x => x.Type == "phone_number")?.Value ?? "",
|
||||
SecurityNumber = claims.Claims.FirstOrDefault(x => x.Type == "card_security_number")?.Value ?? "",
|
||||
State = claims.Claims.FirstOrDefault(x => x.Type == "address_state")?.Value ?? "",
|
||||
Street = claims.Claims.FirstOrDefault(x => x.Type == "address_street")?.Value ?? "",
|
||||
ZipCode = claims.Claims.FirstOrDefault(x => x.Type == "address_zip_code")?.Value ?? ""
|
||||
};
|
||||
}
|
||||
throw new ArgumentException(message: "The principal must be a ClaimsPrincipal", paramName: nameof(principal));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,30 +16,18 @@ namespace WebMVC.Services.Utilities
|
||||
_client = new HttpClient();
|
||||
_logger = new LoggerFactory().CreateLogger(nameof(HttpApiClientWrapper));
|
||||
}
|
||||
|
||||
public Task<string> GetStringAsync(string uri) =>
|
||||
_client.GetStringAsync(uri);
|
||||
|
||||
public async Task<string> GetStringAsync(string uri)
|
||||
{
|
||||
return await HttpInvoker(async () =>
|
||||
await _client.GetStringAsync(uri));
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item)
|
||||
public Task<HttpResponseMessage> PostAsync<T>(string uri, T item)
|
||||
{
|
||||
var contentString = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");
|
||||
return await HttpInvoker(async () =>
|
||||
await _client.PostAsync(uri, contentString));
|
||||
return _client.PostAsync(uri, contentString);
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> DeleteAsync(string uri)
|
||||
{
|
||||
return await HttpInvoker(async () =>
|
||||
await _client.DeleteAsync(uri));
|
||||
}
|
||||
|
||||
private async Task<T> HttpInvoker<T>(Func<Task<T>> action)
|
||||
{
|
||||
return await action();
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(string uri) =>
|
||||
_client.DeleteAsync(uri);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,76 +24,74 @@ namespace WebMVC.Services.Utilities
|
||||
CreateRetryPolicy(),
|
||||
CreateCircuitBreakerPolicy()
|
||||
);
|
||||
}
|
||||
|
||||
private Policy CreateCircuitBreakerPolicy()
|
||||
{
|
||||
return Policy
|
||||
.Handle<HttpRequestException>()
|
||||
.CircuitBreakerAsync(
|
||||
// number of exceptions before breaking circuit
|
||||
3,
|
||||
// time circuit opened before retry
|
||||
TimeSpan.FromMinutes(1),
|
||||
(exception, duration) => {
|
||||
// on circuit opened
|
||||
_logger.LogTrace("Circuit breaker opened");
|
||||
},
|
||||
() => {
|
||||
// on circuit closed
|
||||
_logger.LogTrace("Circuit breaker reset");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private Policy CreateRetryPolicy()
|
||||
{
|
||||
return Policy
|
||||
.Handle<HttpRequestException>()
|
||||
.WaitAndRetryAsync(
|
||||
// number of retries
|
||||
3,
|
||||
// exponential backofff
|
||||
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||
// on retry
|
||||
(exception, timeSpan, retryCount, context) =>
|
||||
{
|
||||
_logger.LogTrace($"Retry {retryCount} " +
|
||||
$"of {context.PolicyKey} " +
|
||||
$"at {context.ExecutionKey}, " +
|
||||
$"due to: {exception}.");
|
||||
});
|
||||
}
|
||||
private Policy CreateCircuitBreakerPolicy() =>
|
||||
Policy.Handle<HttpRequestException>()
|
||||
.CircuitBreakerAsync(
|
||||
// number of exceptions before breaking circuit
|
||||
3,
|
||||
// time circuit opened before retry
|
||||
TimeSpan.FromMinutes(1),
|
||||
(exception, duration) =>
|
||||
{
|
||||
// on circuit opened
|
||||
_logger.LogTrace("Circuit breaker opened");
|
||||
},
|
||||
() =>
|
||||
{
|
||||
// on circuit closed
|
||||
_logger.LogTrace("Circuit breaker reset");
|
||||
}
|
||||
);
|
||||
|
||||
public async Task<string> GetStringAsync(string uri)
|
||||
{
|
||||
return await HttpInvoker(async () =>
|
||||
await _client.GetStringAsync(uri));
|
||||
}
|
||||
private Policy CreateRetryPolicy() =>
|
||||
Policy.Handle<HttpRequestException>()
|
||||
.WaitAndRetryAsync(
|
||||
// number of retries
|
||||
3,
|
||||
// exponential backofff
|
||||
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||
// on retry
|
||||
(exception, timeSpan, retryCount, context) =>
|
||||
{
|
||||
_logger.LogTrace($"Retry {retryCount} " +
|
||||
$"of {context.PolicyKey} " +
|
||||
$"at {context.ExecutionKey}, " +
|
||||
$"due to: {exception}.");
|
||||
}
|
||||
);
|
||||
|
||||
public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item)
|
||||
{
|
||||
// Notice that these (and other methods below) are Task
|
||||
// returning asynchronous methods. But, they do not
|
||||
// have the 'async' modifier, and do not contain
|
||||
// any 'await statements. In each of these methods,
|
||||
// the only asynchronous call is the last (or only)
|
||||
// statement of the method. In those instances,
|
||||
// a Task returning method that does not use the
|
||||
// async modifier is preferred. The compiler generates
|
||||
// synchronous code for this method, but returns the
|
||||
// task from the underlying asynchronous method. The
|
||||
// generated code does not contain the state machine
|
||||
// generated for asynchronous methods.
|
||||
public Task<string> GetStringAsync(string uri) =>
|
||||
HttpInvoker(() => _client.GetStringAsync(uri));
|
||||
|
||||
public Task<HttpResponseMessage> PostAsync<T>(string uri, T item) =>
|
||||
// a new StringContent must be created for each retry
|
||||
// as it is disposed after each call
|
||||
return await HttpInvoker(async () =>
|
||||
await _client.PostAsync(uri,
|
||||
new StringContent(JsonConvert.SerializeObject(item),
|
||||
System.Text.Encoding.UTF8, "application/json")));
|
||||
}
|
||||
HttpInvoker(() =>_client.PostAsync(uri,
|
||||
new StringContent(JsonConvert.SerializeObject(item),
|
||||
System.Text.Encoding.UTF8, "application/json")));
|
||||
|
||||
public async Task<HttpResponseMessage> DeleteAsync(string uri)
|
||||
{
|
||||
return await HttpInvoker(async () =>
|
||||
await _client.DeleteAsync(uri));
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(string uri) =>
|
||||
HttpInvoker(() => _client.DeleteAsync(uri));
|
||||
|
||||
private async Task<T> HttpInvoker<T>(Func<Task<T>> action)
|
||||
{
|
||||
|
||||
private Task<T> HttpInvoker<T>(Func<Task<T>> action) =>
|
||||
// Executes the action applying all
|
||||
// the policies defined in the wrapper
|
||||
return await _policyWrapper
|
||||
.ExecuteAsync(async () => await action());
|
||||
}
|
||||
_policyWrapper.ExecuteAsync(() => action());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,10 +13,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
|
||||
{
|
||||
private readonly IBasketService _cartSvc;
|
||||
|
||||
public Cart(IBasketService cartSvc)
|
||||
{
|
||||
_cartSvc = cartSvc;
|
||||
}
|
||||
public Cart(IBasketService cartSvc) => _cartSvc = cartSvc;
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
|
||||
{
|
||||
|
@ -12,19 +12,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
|
||||
{
|
||||
private readonly IBasketService _cartSvc;
|
||||
|
||||
public CartList(IBasketService cartSvc)
|
||||
{
|
||||
_cartSvc = cartSvc;
|
||||
}
|
||||
public CartList(IBasketService cartSvc) => _cartSvc = cartSvc;
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
|
||||
{
|
||||
var item = await GetItemsAsync(user);
|
||||
return View(item);
|
||||
}
|
||||
private async Task<Basket> GetItemsAsync(ApplicationUser user)
|
||||
{
|
||||
return await _cartSvc.GetBasket(user);
|
||||
}
|
||||
|
||||
private Task<Basket> GetItemsAsync(ApplicationUser user) => _cartSvc.GetBasket(user);
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,20 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.Annotations
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
var month = value.ToString().Split('/')[0];
|
||||
var year = $"20{value.ToString().Split('/')[1]}";
|
||||
DateTime d = new DateTime(int.Parse(year), int.Parse(month), 1);
|
||||
var monthString = value.ToString().Split('/')[0];
|
||||
var yearString = $"20{value.ToString().Split('/')[1]}";
|
||||
// Use the 'out' variable initializer to simplify
|
||||
// the logic of validating the expiration date
|
||||
if ((int.TryParse(monthString, out var month)) &&
|
||||
(int.TryParse(yearString, out var year)))
|
||||
{
|
||||
DateTime d = new DateTime(year, month, 1);
|
||||
|
||||
return d > DateTime.UtcNow;
|
||||
return d > DateTime.UtcNow;
|
||||
} else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels
|
||||
{
|
||||
public class Basket
|
||||
{
|
||||
public Basket()
|
||||
{
|
||||
Items = new List<BasketItem>();
|
||||
}
|
||||
public List<BasketItem> Items { get; set; }
|
||||
// Use property initializer syntax.
|
||||
// While this is often more useful for read only
|
||||
// auto implemented properties, it can simplify logic
|
||||
// for read/write properties.
|
||||
public List<BasketItem> Items { get; set; } = new List<BasketItem>();
|
||||
public string BuyerId { get; set; }
|
||||
|
||||
public decimal Total()
|
||||
|
@ -9,6 +9,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.CartViewModels
|
||||
public class CartComponentViewModel
|
||||
{
|
||||
public int ItemsCount { get; set; }
|
||||
public string Disabled { get { return (ItemsCount == 0) ? "is-disabled" : ""; } }
|
||||
public string Disabled => (ItemsCount == 0) ? "is-disabled" : "";
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels
|
||||
{
|
||||
public class Order
|
||||
{
|
||||
public Order() {
|
||||
OrderItems = new List<OrderItem>();
|
||||
}
|
||||
|
||||
public string OrderNumber {get;set;}
|
||||
|
||||
public DateTime Date {get;set;}
|
||||
@ -53,7 +49,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels
|
||||
|
||||
public string Buyer { get; set; }
|
||||
|
||||
public List<OrderItem> OrderItems { get; }
|
||||
// See the property initializer syntax below. This
|
||||
// initializes the compiler generated field for this
|
||||
// auto-implemented property.
|
||||
public List<OrderItem> OrderItems { get; } = new List<OrderItem>();
|
||||
|
||||
[Required]
|
||||
public Guid RequestId { get; set; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user