diff --git a/docker-compose.dcproj b/docker-compose.dcproj index 296c4b5e0..21c2d5641 100644 --- a/docker-compose.dcproj +++ b/docker-compose.dcproj @@ -7,7 +7,7 @@ webmvc Linux 2.1 - LaunchBrowser + None diff --git a/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs b/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs index 6536ba721..6121e3939 100644 --- a/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs +++ b/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEvent.cs @@ -34,5 +34,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events [JsonProperty] public Boolean CheckForCustomisation { get; set; } + + /*[JsonProperty] + public String TenantId { get; set; }*/ } } diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs index 44137abae..50500da8e 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs @@ -12,10 +12,14 @@ using RabbitMQ.Client; using RabbitMQ.Client.Events; using RabbitMQ.Client.Exceptions; using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Net; +using System.Net.Http; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; +using System.Web; namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ { @@ -28,15 +32,20 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ private readonly IEventBusSubscriptionsManager _subsManager; private readonly ILifetimeScope _autofac; private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus"; + private static readonly String tenantACustomisationUrl = @"http://tenantacustomisation/"; + private static readonly String tenantManagerUrl = @"http://tenantmanager/"; private readonly int _retryCount; + private IModel _consumerChannel; private string _queueName; public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger logger, - ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, string queueName = null, int retryCount = 5) + ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, string queueName = null, + int retryCount = 5) { - _persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); + _persistentConnection = + persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); _queueName = queueName; @@ -76,18 +85,21 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ var policy = RetryPolicy.Handle() .Or() - .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => - { - _logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, $"{time.TotalSeconds:n1}", ex.Message); - }); + .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), + (ex, time) => + { + _logger.LogWarning(ex, + "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, + $"{time.TotalSeconds:n1}", ex.Message); + }); var eventName = @event.GetType().Name; - _logger.LogWarning("Creating RabbitMQ channel to publish event: {EventId} ({EventName})", @event.Id, eventName); + _logger.LogWarning("Creating RabbitMQ channel to publish event: {EventId} ({EventName})", @event.Id, + eventName); using (var channel = _persistentConnection.CreateModel()) { - _logger.LogWarning("Declaring RabbitMQ exchange to publish event: {EventId}", @event.Id); channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); @@ -115,7 +127,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ public void SubscribeDynamic(string eventName) where TH : IDynamicIntegrationEventHandler { - _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); + _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, + typeof(TH).GetGenericTypeName()); DoInternalSubscription(eventName); _subsManager.AddDynamicSubscription(eventName); @@ -129,7 +142,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ var eventName = _subsManager.GetEventKey(); DoInternalSubscription(eventName); - _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); + _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, + typeof(TH).GetGenericTypeName()); _subsManager.AddSubscription(); StartBasicConsume(); @@ -148,8 +162,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ using (var channel = _persistentConnection.CreateModel()) { channel.QueueBind(queue: _queueName, - exchange: BROKER_NAME, - routingKey: eventName); + exchange: BROKER_NAME, + routingKey: eventName); } } } @@ -239,13 +253,13 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ var channel = _persistentConnection.CreateModel(); channel.ExchangeDeclare(exchange: BROKER_NAME, - type: "direct"); + type: "direct"); channel.QueueDeclare(queue: _queueName, - durable: true, - exclusive: false, - autoDelete: false, - arguments: null); + durable: true, + exclusive: false, + autoDelete: false, + arguments: null); channel.CallbackException += (sender, ea) => { @@ -258,6 +272,60 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ return channel; } + + private async void SendEventToTenant(Object @event) + { + string myJson = JsonConvert.SerializeObject(@event); + using (var client = new HttpClient()) + { + try + { + //TODO replace URL with response from tenantmanager + var response = await client.PostAsync( + tenantACustomisationUrl + "api/OrderStatusChangedToSubmittedIntegrationEvents", + new StringContent(myJson, Encoding.UTF8, "application/json")); + response.EnsureSuccessStatusCode(); + _logger.LogInformation("----- Event sent to tenant{@event} -----", @event); + } + + catch (Exception e) + { + _logger.LogInformation("----- Exception{@e} -- Event{@event} -----", e, @event); + } + } + } + + private async Task IsEventCustomised(String eventName, String tenantId) + { + Boolean isCustomised = false; + + var builder = new UriBuilder(tenantManagerUrl + "api/Customisations"); + builder.Port = -1; + var query = HttpUtility.ParseQueryString(builder.Query); + query["eventName"] = eventName; + query["tenantId"] = tenantId; + builder.Query = query.ToString(); + string url = builder.ToString(); + + using (var client = new HttpClient()) + { + try + { + var response = await client.GetAsync( + url); + response.EnsureSuccessStatusCode(); + isCustomised = + JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result); + } + catch (Exception e) + { + _logger.LogInformation("----- Exception{@e}", e); + } + } + + return isCustomised; + } + private async Task ProcessEvent(string eventName, string message) { _logger.LogWarning("Processing RabbitMQ event: {EventName}", eventName); @@ -271,7 +339,9 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ { if (subscription.IsDynamic) { - var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler; + //TODO check if it is required here aswell + var handler = + scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler; if (handler == null) continue; dynamic eventData = JObject.Parse(message); @@ -281,17 +351,32 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ else { var handler = scope.ResolveOptional(subscription.HandlerType); - if (eventName.Equals("OrderStatusChangedToSubmittedIntegrationEvent") || eventName.Equals("UserCheckoutAcceptedIntegrationEvent")) - { - Debug.WriteLine("Here"); - } + if (handler == null) continue; var eventType = _subsManager.GetEventTypeByName(eventName); var integrationEvent = JsonConvert.DeserializeObject(message, eventType); + //IsEventCustomised(eventName, integrationEvent.TenantId); + if (eventName.Equals("OrderStatusChangedToSubmittedIntegrationEvent") && + integrationEvent is IntegrationEvent) //TODO replace with tenantmanager + { + //Casting + IntegrationEvent evt = (IntegrationEvent) integrationEvent; + //Checking if event should be sent to tenant, or handled normally + //Can instead create an endpoint in the tenant manager that also handles all the events that a tenant wants to postpone + //Additionally, an endpoint in the tenant manager is required, where the tenant + //Issue with the tenant knowing the id of the event + if (evt.CheckForCustomisation) + { + SendEventToTenant(integrationEvent); + break; + } + } + var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); await Task.Yield(); - await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); + await (Task) concreteType.GetMethod("Handle") + .Invoke(handler, new object[] {integrationEvent}); } } } @@ -302,4 +387,4 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ } } } -} +} \ No newline at end of file diff --git a/src/Services/TenantCustomisations/TenantACustomisations/Controllers/OrderStatusChangedToSubmittedIntegrationEventsController.cs b/src/Services/TenantCustomisations/TenantACustomisations/Controllers/OrderStatusChangedToSubmittedIntegrationEventsController.cs new file mode 100644 index 000000000..f42916f62 --- /dev/null +++ b/src/Services/TenantCustomisations/TenantACustomisations/Controllers/OrderStatusChangedToSubmittedIntegrationEventsController.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Microsoft.Extensions.Logging; +using TenantACustomisations.Database; +using TenantACustomisations.IntegrationEvents.Events; + +namespace TenantACustomisations.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class OrderStatusChangedToSubmittedIntegrationEventsController : ControllerBase + { + private readonly TenantAContext _context; + private readonly IEventBus _eventBus; + private readonly ILogger _logger; + + + public OrderStatusChangedToSubmittedIntegrationEventsController(TenantAContext context, IEventBus eventBus, ILogger logger) + { + _context = context; + _eventBus = eventBus; + _logger = logger; + } + + // GET: api/OrderStatusChangedToSubmittedIntegrationEvents + [HttpGet] + public async Task>> GetOrderStatusChangedToSubmittedIntegrationEvent(String orderId) + { + if (String.IsNullOrEmpty(orderId)) + { + return await _context.OrderStatusChangedToSubmittedIntegrationEvent.ToListAsync(); + } + else + { + var orderStatusChangedToSubmittedIntegrationEvent = _context.OrderStatusChangedToSubmittedIntegrationEvent.Where(x => x.OrderId == Int32.Parse(orderId)).ToListAsync(); + + return await orderStatusChangedToSubmittedIntegrationEvent; + } + } + + // GET: api/OrderStatusChangedToSubmittedIntegrationEvents/5 + [HttpGet("{id}")] + public async Task> GetOrderStatusChangedToSubmittedIntegrationEvent(Guid id) + { + var orderStatusChangedToSubmittedIntegrationEvent = await _context.OrderStatusChangedToSubmittedIntegrationEvent.FindAsync(id); + + if (orderStatusChangedToSubmittedIntegrationEvent == null) + { + return NotFound(); + } + + return orderStatusChangedToSubmittedIntegrationEvent; + } + + // PUT: api/OrderStatusChangedToSubmittedIntegrationEvents/5 + [HttpPut("{id}")] + public async Task PutOrderStatusChangedToSubmittedIntegrationEvent(Guid id, OrderStatusChangedToSubmittedIntegrationEvent orderStatusChangedToSubmittedIntegrationEvent) + { + if (id != orderStatusChangedToSubmittedIntegrationEvent.Id) + { + return BadRequest(); + } + + _context.Entry(orderStatusChangedToSubmittedIntegrationEvent).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!OrderStatusChangedToSubmittedIntegrationEventExists(id)) + { + return NotFound(); + } + else + { + throw; + } + } + + return NoContent(); + } + + // POST: api/OrderStatusChangedToSubmittedIntegrationEvents + [HttpPost] + public async Task> PostOrderStatusChangedToSubmittedIntegrationEvent(OrderStatusChangedToSubmittedIntegrationEvent orderStatusChangedToSubmittedIntegrationEvent) + { + _context.OrderStatusChangedToSubmittedIntegrationEvent.Add(orderStatusChangedToSubmittedIntegrationEvent); + await _context.SaveChangesAsync(); + + return CreatedAtAction("GetOrderStatusChangedToSubmittedIntegrationEvent", new { id = orderStatusChangedToSubmittedIntegrationEvent.Id }, orderStatusChangedToSubmittedIntegrationEvent); + } + + // DELETE: api/OrderStatusChangedToSubmittedIntegrationEvents/5 + [HttpDelete("{id}")] + public async Task> DeleteOrderStatusChangedToSubmittedIntegrationEvent(Guid id) + { + var orderStatusChangedToSubmittedIntegrationEvent = await _context.OrderStatusChangedToSubmittedIntegrationEvent.FindAsync(id); + if (orderStatusChangedToSubmittedIntegrationEvent == null) + { + return NotFound(); + } + + try + { + _logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from OrderStatusChangedToSubmittedIntegrationEventsController - ({@IntegrationEvent})", orderStatusChangedToSubmittedIntegrationEvent.Id, orderStatusChangedToSubmittedIntegrationEvent); + orderStatusChangedToSubmittedIntegrationEvent.CheckForCustomisation = false; + _eventBus.Publish(orderStatusChangedToSubmittedIntegrationEvent); + _context.OrderStatusChangedToSubmittedIntegrationEvent.Remove(orderStatusChangedToSubmittedIntegrationEvent); + await _context.SaveChangesAsync(); + return orderStatusChangedToSubmittedIntegrationEvent; + } + catch (Exception ex) + { + _logger.LogError(ex, "ERROR Publishing integration event: {IntegrationEventId} from OrderStatusChangedToSubmittedIntegrationEventsController", orderStatusChangedToSubmittedIntegrationEvent.Id); + + throw; + } + } + + private bool OrderStatusChangedToSubmittedIntegrationEventExists(Guid id) + { + return _context.OrderStatusChangedToSubmittedIntegrationEvent.Any(e => e.Id == id); + } + } +} diff --git a/src/Services/TenantCustomisations/TenantACustomisations/Database/TenantAContext.cs b/src/Services/TenantCustomisations/TenantACustomisations/Database/TenantAContext.cs index 0f893e3b5..d435fbf14 100644 --- a/src/Services/TenantCustomisations/TenantACustomisations/Database/TenantAContext.cs +++ b/src/Services/TenantCustomisations/TenantACustomisations/Database/TenantAContext.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using TenantACustomisations.ExternalServices; +using TenantACustomisations.IntegrationEvents.Events; namespace TenantACustomisations.Database { @@ -17,6 +18,12 @@ namespace TenantACustomisations.Database public DbSet ShippingInformation { get; set; } + public DbSet OrderStatusChangedToSubmittedIntegrationEvent + { + get; + set; + } + } public class TenantAContextDesignFactory : IDesignTimeDbContextFactory { diff --git a/src/Services/TenantCustomisations/TenantACustomisations/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs b/src/Services/TenantCustomisations/TenantACustomisations/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs index 12a759508..1b929c3c4 100644 --- a/src/Services/TenantCustomisations/TenantACustomisations/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs +++ b/src/Services/TenantCustomisations/TenantACustomisations/IntegrationEvents/Events/OrderStatusChangedToSubmittedIntegrationEvent.cs @@ -8,9 +8,9 @@ namespace TenantACustomisations.IntegrationEvents.Events { public class OrderStatusChangedToSubmittedIntegrationEvent : IntegrationEvent { - public int OrderId { get; } - public string OrderStatus { get; } - public string BuyerName { get; } + public int OrderId { get; set; } + public string OrderStatus { get; set; } + public string BuyerName { get; set; } public OrderStatusChangedToSubmittedIntegrationEvent(int orderId, string orderStatus, string buyerName) { diff --git a/src/Web/WebMVC/Controllers/OrderController.cs b/src/Web/WebMVC/Controllers/OrderController.cs index 1c3cff632..5d70228cd 100644 --- a/src/Web/WebMVC/Controllers/OrderController.cs +++ b/src/Web/WebMVC/Controllers/OrderController.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.eShopOnContainers.WebMVC.ViewModels.Customisation; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Polly.CircuitBreaker; using System; @@ -11,6 +12,7 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; +using System.Web; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { @@ -20,18 +22,21 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers private IOrderingService _orderSvc; private IBasketService _basketSvc; private readonly IIdentityParser _appUserParser; - private static String url = @"http://tenantacustomisation/"; + private static String tenantACustomisationsUrl = @"http://tenantacustomisation/"; + private readonly ILogger _logger; - public OrderController(IOrderingService orderSvc, IBasketService basketSvc, IIdentityParser appUserParser) + + public OrderController(IOrderingService orderSvc, IBasketService basketSvc, + IIdentityParser appUserParser, ILogger logger) { _appUserParser = appUserParser; _orderSvc = orderSvc; _basketSvc = basketSvc; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task Create() { - var user = _appUserParser.Parse(HttpContext.User); var order = await _basketSvc.GetOrderDraft(user.Id); var vm = _orderSvc.MapUserInfoIntoOrder(user, order); @@ -58,7 +63,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers } catch (BrokenCircuitException) { - ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)"); + ModelState.AddModelError("Error", + "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)"); } return View("Create", model); @@ -75,6 +81,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers public async Task Detail(string orderId) { var user = _appUserParser.Parse(HttpContext.User); + Boolean RFIDScanned = await AllGoodsRFIDScanned(orderId); + ViewData["RFIDScanned"] = RFIDScanned; var order = await _orderSvc.GetOrder(user, orderId); return View(order); @@ -85,34 +93,63 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers var user = _appUserParser.Parse(HttpContext.User); var vm = await _orderSvc.GetMyOrders(user); List shippingInformation = GetShippingInfo(vm); + _logger.LogInformation("----- Shipping info{@ShippingInformation}", shippingInformation); + ViewData["ShippingInfo"] = shippingInformation; return View(vm); } + + private async Task AllGoodsRFIDScanned(String orderId) + { + var builder = new UriBuilder(tenantACustomisationsUrl + "api/OrderStatusChangedToSubmittedIntegrationEvents"); + builder.Port = -1; + var query = HttpUtility.ParseQueryString(builder.Query); + query["orderId"] = orderId; + builder.Query = query.ToString(); + string url = builder.ToString(); + + using (var client = new HttpClient()) + { + var response = await client.GetAsync( + url); + if (response.StatusCode.Equals(HttpStatusCode.NotFound)) + { + return true; + } + + return false; + } + } + private List GetShippingInfo(List orders) { List shippingInformation = new List(); - using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate })) + using (var client = new HttpClient(new HttpClientHandler + {AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate})) { - client.BaseAddress = new Uri(url); + client.BaseAddress = new Uri(tenantACustomisationsUrl); try { - HttpResponseMessage response = client.GetAsync("api/shippinginformation").Result; + HttpResponseMessage response = client.GetAsync("api/shippinginformations").Result; response.EnsureSuccessStatusCode(); string result = response.Content.ReadAsStringAsync().Result; - List results = JsonConvert.DeserializeObject>(result); - results.ForEach( s => + _logger.LogInformation("----- Result{@result} -----", result); + + List + results = JsonConvert.DeserializeObject>(result); + results.ForEach(s => { - if(orders.Any(item => item.OrderNumber.Equals(s.OrderNumber))) + if (orders.Any(item => item.OrderNumber.Equals(s.OrderNumber))) { shippingInformation.Add(s); } }); - } catch (Exception e) { Console.WriteLine(e); + _logger.LogInformation("----- Exception{@e} -----", e); } } diff --git a/src/Web/WebMVC/Views/Order/Detail.cshtml b/src/Web/WebMVC/Views/Order/Detail.cshtml index 6b7c0b46e..41158463a 100644 --- a/src/Web/WebMVC/Views/Order/Detail.cshtml +++ b/src/Web/WebMVC/Views/Order/Detail.cshtml @@ -3,9 +3,12 @@ @model Microsoft.eShopOnContainers.WebMVC.ViewModels.Order @{ - ViewData["Title"] = "Order Detail"; - var headerList= new List
() { - new Header() { Controller = "Catalog", Text = "Back to catalog" } }; + ViewData["Title"] = "Order Detail"; + var headerList = new List
() + { + new Header() {Controller = "Catalog", Text = "Back to catalog"} + }; + var rfidScanned = ViewData["RFIDScanned"]; }
@@ -14,20 +17,22 @@
-
Order number
-
Date
-
Total
-
Status
+
Order number
+
Date
+
Total
+
Status
+
RFID Scanned
-
@Model.OrderNumber
-
@Model.Date
-
$@Model.Total
-
@Model.Status
+
$@Model.Total
+
@Model.OrderNumber
+
@Model.Date
+
@Model.Status
+
@rfidScanned
- +
Description
@@ -88,4 +93,4 @@
-
+ \ No newline at end of file diff --git a/src/Web/WebMVC/Views/Order/Index.cshtml b/src/Web/WebMVC/Views/Order/Index.cshtml index 48da48d1f..d0eb4fe0e 100644 --- a/src/Web/WebMVC/Views/Order/Index.cshtml +++ b/src/Web/WebMVC/Views/Order/Index.cshtml @@ -18,7 +18,7 @@
-
Order number
+
Order number
Date
Total
Status
@@ -32,26 +32,29 @@ foreach (var item in Model) {
-
@Html.DisplayFor(modelItem => item.OrderNumber)
-
@Html.DisplayFor(modelItem => item.Date)
+
@Html.DisplayFor(modelItem => item.OrderNumber)
+
@item.Date.ToShortDateString()
$ @Html.DisplayFor(modelItem => item.Total)
@Html.DisplayFor(modelItem => item.Status)
@for (var i = 0; i < shippingInfo.Count(); i++) { var si = shippingInfo[i]; - if (si.OrderNumber.Equals(item.OrderNumber)){ - @si.ShippingTime + if (si.OrderNumber.Equals(item.OrderNumber)) + { + @si.ShippingTime.ToShortDateString(); + break; } } -
+
@for (var i = 0; i < shippingInfo.Count(); i++) { var si = shippingInfo[i]; if (si.OrderNumber.Equals(item.OrderNumber)) { - @si.ArrivalTime + @si.ArrivalTime.ToShortDateString(); + break; } }