Merge pull request #126 from BillWagner/csharp7-on-mvcapp
C# 7 language feature updates
This commit is contained in:
commit
cc98475182
@ -11,16 +11,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
public class AccountController : Controller
|
public class AccountController : Controller
|
||||||
{
|
{
|
||||||
private readonly IIdentityParser<ApplicationUser> _identityParser;
|
private readonly IIdentityParser<ApplicationUser> _identityParser;
|
||||||
public AccountController(IIdentityParser<ApplicationUser> identityParser)
|
public AccountController(IIdentityParser<ApplicationUser> identityParser) =>
|
||||||
{
|
|
||||||
_identityParser = identityParser;
|
_identityParser = identityParser;
|
||||||
}
|
|
||||||
|
|
||||||
public ActionResult Index()
|
|
||||||
{
|
|
||||||
return View();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public ActionResult Index() => View();
|
||||||
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public IActionResult SignIn(string returnUrl)
|
public IActionResult SignIn(string returnUrl)
|
||||||
{
|
{
|
||||||
|
@ -14,10 +14,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
{
|
{
|
||||||
private ICatalogService _catalogSvc;
|
private ICatalogService _catalogSvc;
|
||||||
|
|
||||||
public CatalogController(ICatalogService catalogSvc)
|
public CatalogController(ICatalogService catalogSvc) =>
|
||||||
{
|
|
||||||
_catalogSvc = catalogSvc;
|
_catalogSvc = catalogSvc;
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IActionResult> Index(int? BrandFilterApplied, int? TypesFilterApplied, int? page)
|
public async Task<IActionResult> Index(int? BrandFilterApplied, int? TypesFilterApplied, int? page)
|
||||||
{
|
{
|
||||||
@ -35,7 +33,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
ActualPage = page ?? 0,
|
ActualPage = page ?? 0,
|
||||||
ItemsPerPage = catalog.Data.Count,
|
ItemsPerPage = catalog.Data.Count,
|
||||||
TotalItems = catalog.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);
|
return View(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult Error()
|
public IActionResult Error() => View();
|
||||||
{
|
|
||||||
return View();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,20 +11,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Extensions
|
|||||||
{
|
{
|
||||||
public static class HttpClientExtensions
|
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);
|
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);
|
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);
|
client.SetToken(JwtConstants.TokenType, token);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BasicAuthenticationHeaderValue : AuthenticationHeaderValue
|
public class BasicAuthenticationHeaderValue : AuthenticationHeaderValue
|
||||||
|
@ -8,10 +8,8 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
public static class SessionExtensions
|
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));
|
session.SetString(key, JsonConvert.SerializeObject(value));
|
||||||
}
|
|
||||||
|
|
||||||
public static T GetObject<T>(this ISession session, string key)
|
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);
|
_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 dataString = await _apiClient.GetStringAsync(basketUrl);
|
||||||
var response = JsonConvert.DeserializeObject<Basket>(dataString);
|
// Use the ?? Null conditional operator to simplify the initialization of response
|
||||||
if (response == null)
|
var response = JsonConvert.DeserializeObject<Basket>(dataString) ??
|
||||||
{
|
new Basket()
|
||||||
response = new Basket()
|
|
||||||
{
|
{
|
||||||
BuyerId = user.Id
|
BuyerId = user.Id
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -67,9 +65,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
basket.Items.ForEach(x =>
|
basket.Items.ForEach(x =>
|
||||||
{
|
{
|
||||||
var quantity = quantities.Where(y => y.Key == x.Id).FirstOrDefault();
|
// Simplify this logic by using the
|
||||||
if (quantities.Where(y => y.Key == x.Id).Count() > 0)
|
// new out variable initializer.
|
||||||
x.Quantity = quantity.Value;
|
if (quantities.TryGetValue(x.Id, out var quantity))
|
||||||
|
{
|
||||||
|
x.Quantity = quantity;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return basket;
|
return basket;
|
||||||
@ -119,7 +120,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
var token = await context.Authentication.GetTokenAsync("access_token");
|
var token = await context.Authentication.GetTokenAsync("access_token");
|
||||||
|
|
||||||
_apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", 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);
|
var response = await _apiClient.DeleteAsync(basketUrl);
|
||||||
|
|
||||||
//CCE: response status code...
|
//CCE: response status code...
|
||||||
|
@ -61,8 +61,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
JArray brands = JArray.Parse(dataString);
|
JArray brands = JArray.Parse(dataString);
|
||||||
foreach (JObject brand in brands.Children<JObject>())
|
foreach (JObject brand in brands.Children<JObject>())
|
||||||
{
|
{
|
||||||
dynamic item = brand;
|
items.Add(new SelectListItem()
|
||||||
items.Add(new SelectListItem() { Value = item.id, Text = item.brand });
|
{
|
||||||
|
Value = brand.Value<string>("id"),
|
||||||
|
Text = brand.Value<string>("brand")
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
@ -79,10 +82,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
JArray brands = JArray.Parse(dataString);
|
JArray brands = JArray.Parse(dataString);
|
||||||
foreach (JObject brand in brands.Children<JObject>())
|
foreach (JObject brand in brands.Children<JObject>())
|
||||||
{
|
{
|
||||||
dynamic item = brand;
|
items.Add(new SelectListItem()
|
||||||
items.Add(new SelectListItem() { Value = item.id, Text = item.type });
|
{
|
||||||
|
Value = brand.Value<string>("id"),
|
||||||
|
Text = brand.Value<string>("type")
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,26 +12,31 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
{
|
{
|
||||||
public ApplicationUser Parse(IPrincipal principal)
|
public ApplicationUser Parse(IPrincipal principal)
|
||||||
{
|
{
|
||||||
var user = new ApplicationUser();
|
// Pattern matching 'is' expression
|
||||||
var claims = (ClaimsPrincipal)principal;
|
// 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 : "";
|
CardHolderName = claims.Claims.FirstOrDefault(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 : "";
|
CardNumber = claims.Claims.FirstOrDefault(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 : "";
|
Expiration = claims.Claims.FirstOrDefault(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;
|
CardType = int.Parse(claims.Claims.FirstOrDefault(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 : "";
|
City = claims.Claims.FirstOrDefault(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 : "";
|
Country = claims.Claims.FirstOrDefault(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 : "";
|
Email = claims.Claims.FirstOrDefault(x => x.Type == "email")?.Value ?? "",
|
||||||
user.Id = (claims.Claims.Where(x => x.Type == "sub").Count() > 0) ? claims.Claims.First(x => x.Type == "sub").Value : "";
|
Id = claims.Claims.FirstOrDefault(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 : "";
|
LastName = claims.Claims.FirstOrDefault(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 : "";
|
Name = claims.Claims.FirstOrDefault(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 : "";
|
PhoneNumber = claims.Claims.FirstOrDefault(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 : "";
|
SecurityNumber = claims.Claims.FirstOrDefault(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 : "";
|
State = claims.Claims.FirstOrDefault(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 : "";
|
Street = claims.Claims.FirstOrDefault(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 : "";
|
ZipCode = claims.Claims.FirstOrDefault(x => x.Type == "address_zip_code")?.Value ?? ""
|
||||||
|
};
|
||||||
return user;
|
}
|
||||||
|
throw new ArgumentException(message: "The principal must be a ClaimsPrincipal", paramName: nameof(principal));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,30 +16,18 @@ namespace WebMVC.Services.Utilities
|
|||||||
_client = new HttpClient();
|
_client = new HttpClient();
|
||||||
_logger = new LoggerFactory().CreateLogger(nameof(HttpApiClientWrapper));
|
_logger = new LoggerFactory().CreateLogger(nameof(HttpApiClientWrapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<string> GetStringAsync(string uri) =>
|
||||||
|
_client.GetStringAsync(uri);
|
||||||
|
|
||||||
public async Task<string> GetStringAsync(string uri)
|
public Task<HttpResponseMessage> PostAsync<T>(string uri, T item)
|
||||||
{
|
|
||||||
return await HttpInvoker(async () =>
|
|
||||||
await _client.GetStringAsync(uri));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item)
|
|
||||||
{
|
{
|
||||||
var contentString = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");
|
var contentString = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");
|
||||||
return await HttpInvoker(async () =>
|
return _client.PostAsync(uri, contentString);
|
||||||
await _client.PostAsync(uri, contentString));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<HttpResponseMessage> DeleteAsync(string uri)
|
public Task<HttpResponseMessage> DeleteAsync(string uri) =>
|
||||||
{
|
_client.DeleteAsync(uri);
|
||||||
return await HttpInvoker(async () =>
|
|
||||||
await _client.DeleteAsync(uri));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<T> HttpInvoker<T>(Func<Task<T>> action)
|
|
||||||
{
|
|
||||||
return await action();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,76 +24,74 @@ namespace WebMVC.Services.Utilities
|
|||||||
CreateRetryPolicy(),
|
CreateRetryPolicy(),
|
||||||
CreateCircuitBreakerPolicy()
|
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()
|
private Policy CreateCircuitBreakerPolicy() =>
|
||||||
{
|
Policy.Handle<HttpRequestException>()
|
||||||
return Policy
|
.CircuitBreakerAsync(
|
||||||
.Handle<HttpRequestException>()
|
// number of exceptions before breaking circuit
|
||||||
.WaitAndRetryAsync(
|
3,
|
||||||
// number of retries
|
// time circuit opened before retry
|
||||||
3,
|
TimeSpan.FromMinutes(1),
|
||||||
// exponential backofff
|
(exception, duration) =>
|
||||||
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
{
|
||||||
// on retry
|
// on circuit opened
|
||||||
(exception, timeSpan, retryCount, context) =>
|
_logger.LogTrace("Circuit breaker opened");
|
||||||
{
|
},
|
||||||
_logger.LogTrace($"Retry {retryCount} " +
|
() =>
|
||||||
$"of {context.PolicyKey} " +
|
{
|
||||||
$"at {context.ExecutionKey}, " +
|
// on circuit closed
|
||||||
$"due to: {exception}.");
|
_logger.LogTrace("Circuit breaker reset");
|
||||||
});
|
}
|
||||||
}
|
);
|
||||||
|
|
||||||
public async Task<string> GetStringAsync(string uri)
|
private Policy CreateRetryPolicy() =>
|
||||||
{
|
Policy.Handle<HttpRequestException>()
|
||||||
return await HttpInvoker(async () =>
|
.WaitAndRetryAsync(
|
||||||
await _client.GetStringAsync(uri));
|
// 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
|
// a new StringContent must be created for each retry
|
||||||
// as it is disposed after each call
|
// as it is disposed after each call
|
||||||
return await HttpInvoker(async () =>
|
HttpInvoker(() =>_client.PostAsync(uri,
|
||||||
await _client.PostAsync(uri,
|
new StringContent(JsonConvert.SerializeObject(item),
|
||||||
new StringContent(JsonConvert.SerializeObject(item),
|
System.Text.Encoding.UTF8, "application/json")));
|
||||||
System.Text.Encoding.UTF8, "application/json")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HttpResponseMessage> DeleteAsync(string uri)
|
public Task<HttpResponseMessage> DeleteAsync(string uri) =>
|
||||||
{
|
HttpInvoker(() => _client.DeleteAsync(uri));
|
||||||
return await HttpInvoker(async () =>
|
|
||||||
await _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
|
// Executes the action applying all
|
||||||
// the policies defined in the wrapper
|
// the policies defined in the wrapper
|
||||||
return await _policyWrapper
|
_policyWrapper.ExecuteAsync(() => action());
|
||||||
.ExecuteAsync(async () => await action());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
|
|||||||
{
|
{
|
||||||
private readonly IBasketService _cartSvc;
|
private readonly IBasketService _cartSvc;
|
||||||
|
|
||||||
public Cart(IBasketService cartSvc)
|
public Cart(IBasketService cartSvc) => _cartSvc = cartSvc;
|
||||||
{
|
|
||||||
_cartSvc = cartSvc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
|
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
|
||||||
{
|
{
|
||||||
|
@ -12,19 +12,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
|
|||||||
{
|
{
|
||||||
private readonly IBasketService _cartSvc;
|
private readonly IBasketService _cartSvc;
|
||||||
|
|
||||||
public CartList(IBasketService cartSvc)
|
public CartList(IBasketService cartSvc) => _cartSvc = cartSvc;
|
||||||
{
|
|
||||||
_cartSvc = cartSvc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
|
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
|
||||||
{
|
{
|
||||||
var item = await GetItemsAsync(user);
|
var item = await GetItemsAsync(user);
|
||||||
return View(item);
|
return View(item);
|
||||||
}
|
}
|
||||||
private async Task<Basket> GetItemsAsync(ApplicationUser user)
|
|
||||||
{
|
private Task<Basket> GetItemsAsync(ApplicationUser user) => _cartSvc.GetBasket(user);
|
||||||
return await _cartSvc.GetBasket(user);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,20 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.Annotations
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var month = value.ToString().Split('/')[0];
|
var monthString = value.ToString().Split('/')[0];
|
||||||
var year = $"20{value.ToString().Split('/')[1]}";
|
var yearString = $"20{value.ToString().Split('/')[1]}";
|
||||||
DateTime d = new DateTime(int.Parse(year), int.Parse(month), 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 class Basket
|
||||||
{
|
{
|
||||||
public Basket()
|
// Use property initializer syntax.
|
||||||
{
|
// While this is often more useful for read only
|
||||||
Items = new List<BasketItem>();
|
// auto implemented properties, it can simplify logic
|
||||||
}
|
// for read/write properties.
|
||||||
public List<BasketItem> Items { get; set; }
|
public List<BasketItem> Items { get; set; } = new List<BasketItem>();
|
||||||
public string BuyerId { get; set; }
|
public string BuyerId { get; set; }
|
||||||
|
|
||||||
public decimal Total()
|
public decimal Total()
|
||||||
|
@ -9,6 +9,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.CartViewModels
|
|||||||
public class CartComponentViewModel
|
public class CartComponentViewModel
|
||||||
{
|
{
|
||||||
public int ItemsCount { get; set; }
|
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 class Order
|
||||||
{
|
{
|
||||||
public Order() {
|
|
||||||
OrderItems = new List<OrderItem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string OrderNumber {get;set;}
|
public string OrderNumber {get;set;}
|
||||||
|
|
||||||
public DateTime Date {get;set;}
|
public DateTime Date {get;set;}
|
||||||
@ -53,7 +49,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels
|
|||||||
|
|
||||||
public string Buyer { get; set; }
|
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]
|
[Required]
|
||||||
public Guid RequestId { get; set; }
|
public Guid RequestId { get; set; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user