Skip to content

Commit 7dc3208

Browse files
committed
adding second large function project to Ex8
1 parent dfd87c3 commit 7dc3208

3 files changed

Lines changed: 344 additions & 2 deletions

File tree

Lines changed: 210 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,210 @@
1-
// See https://aka.ms/new-console-template for more information
2-
Console.WriteLine("Hello, World!");
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
5+
namespace OnlineStore;
6+
7+
// Main order processing logic with a large method
8+
public class OrderProcessor
9+
{
10+
// Simulated external services (stubs for inventory, payment, shipping, notification)
11+
private static InventoryService InventoryService = new InventoryService();
12+
private static PaymentGateway PaymentGateway = new PaymentGateway();
13+
private static ShippingService ShippingService = new ShippingService();
14+
private static NotificationService NotificationService = new NotificationService();
15+
16+
public OrderResult ProcessOrder(Order order)
17+
{
18+
// Step 1: Validate Order Details (basic checks on input)
19+
if (order == null)
20+
{
21+
return OrderResult.Failure("No order provided");
22+
}
23+
if (order.Items == null || order.Items.Count == 0)
24+
{
25+
return OrderResult.Failure("Order has no items");
26+
}
27+
if (string.IsNullOrWhiteSpace(order.ShippingAddress) || string.IsNullOrWhiteSpace(order.CustomerEmail))
28+
{
29+
return OrderResult.Failure("Missing shipping address or customer email");
30+
}
31+
if (order.PaymentInfo == null || string.IsNullOrWhiteSpace(order.PaymentInfo.CardNumber))
32+
{
33+
return OrderResult.Failure("Payment information is incomplete");
34+
}
35+
Console.WriteLine($"Processing Order {order.Id} for {order.CustomerEmail}...");
36+
37+
// Step 2: Check and Reserve Inventory
38+
foreach (OrderItem item in order.Items)
39+
{
40+
bool inStock = InventoryService.CheckStock(item.ProductId, item.Quantity);
41+
if (!inStock)
42+
{
43+
Console.WriteLine($"Item {item.ProductId} is out of stock. Aborting order.");
44+
return OrderResult.Failure($"Item {item.ProductId} is out of stock");
45+
}
46+
}
47+
bool inventoryReserved = InventoryService.ReserveStock(order.Items);
48+
if (!inventoryReserved)
49+
{
50+
Console.WriteLine("Failed to reserve inventory for the order.");
51+
return OrderResult.Failure("Inventory reservation failed");
52+
}
53+
Console.WriteLine("Inventory reserved successfully.");
54+
55+
// Step 3: Process Payment
56+
try
57+
{
58+
// Attempt to charge the customer's card
59+
PaymentGateway.Charge(order.PaymentInfo, order.TotalAmount);
60+
Console.WriteLine("Payment processed successfully.");
61+
}
62+
catch (PaymentException ex)
63+
{
64+
// If payment fails, release reserved stock and return failure
65+
InventoryService.ReleaseStock(order.Items);
66+
Console.WriteLine($"Payment failed for Order {order.Id}: {ex.Message}");
67+
return OrderResult.Failure("Payment processing failed");
68+
}
69+
70+
// Step 4: Schedule Shipping
71+
try
72+
{
73+
ShippingService.ScheduleShipment(order);
74+
Console.WriteLine("Shipping scheduled successfully.");
75+
}
76+
catch (Exception ex)
77+
{
78+
Console.WriteLine($"Error scheduling shipment: {ex.Message}");
79+
return OrderResult.Failure("Shipping scheduling failed");
80+
}
81+
82+
// Step 5: Send Confirmation
83+
try
84+
{
85+
NotificationService.SendOrderConfirmation(order.CustomerEmail, order.Id);
86+
Console.WriteLine($"Confirmation sent to {order.CustomerEmail}.");
87+
}
88+
catch (Exception ex)
89+
{
90+
// If confirmation fails, log a warning but do not abort the order
91+
Console.WriteLine($"Warning: failed to send confirmation email: {ex.Message}");
92+
}
93+
94+
// Step 6: Finalize Order
95+
order.Status = OrderStatus.Completed;
96+
// (In a real app, update the order record in a database here)
97+
Console.WriteLine($"Order {order.Id} is completed and closed out in the system.");
98+
99+
return OrderResult.Success(order.Id);
100+
}
101+
}
102+
103+
// Supporting data classes and result type
104+
public class Order
105+
{
106+
public string Id { get; set; }
107+
public List<OrderItem> Items { get; set; }
108+
public string CustomerEmail { get; set; }
109+
public string ShippingAddress { get; set; }
110+
public PaymentInfo PaymentInfo { get; set; }
111+
public decimal TotalAmount { get; set; }
112+
public OrderStatus Status { get; set; }
113+
}
114+
public class OrderItem
115+
{
116+
public string ProductId { get; set; }
117+
public int Quantity { get; set; }
118+
// Price, etc., could be added for a full implementation
119+
}
120+
public class PaymentInfo
121+
{
122+
public string CardNumber { get; set; }
123+
public string CardCVV { get; set; }
124+
public string CardHolderName { get; set; }
125+
public string BillingAddress { get; set; }
126+
// Expiry date, etc., could be included
127+
}
128+
public enum OrderStatus
129+
{
130+
Pending, Completed, Cancelled
131+
}
132+
public class OrderResult
133+
{
134+
public bool IsSuccess { get; private set; }
135+
public string OrderId { get; private set; }
136+
public string ErrorMessage { get; private set; }
137+
private OrderResult(bool success, string orderId = null, string error = null)
138+
{
139+
IsSuccess = success; OrderId = orderId; ErrorMessage = error;
140+
}
141+
public static OrderResult Success(string id) => new OrderResult(true, orderId: id);
142+
public static OrderResult Failure(string error) => new OrderResult(false, error: error);
143+
}
144+
145+
// Custom exception for payment errors
146+
public class PaymentException : Exception
147+
{
148+
public PaymentException(string message) : base(message) { }
149+
}
150+
// Simulated external services:
151+
public class InventoryService
152+
{
153+
// In a real app, this would check a database or API
154+
public bool CheckStock(string productId, int quantity)
155+
{
156+
// Fake logic: let's assume everything is in stock for this demo
157+
return true;
158+
}
159+
public bool ReserveStock(List<OrderItem> items)
160+
{
161+
// Fake reservation always succeeds (would actually decrement stock)
162+
return true;
163+
}
164+
public void ReleaseStock(List<OrderItem> items)
165+
{
166+
// Would add the items back to stock in a real system
167+
}
168+
}
169+
public class PaymentGateway
170+
{
171+
public void Charge(PaymentInfo payment, decimal amount)
172+
{
173+
// Very basic simulation: throw if card data looks invalid or a specific test card
174+
if (string.IsNullOrEmpty(payment.CardNumber) || payment.CardNumber.Length < 44)
175+
{
176+
throw new PaymentException("Invalid card data");
177+
}
178+
if (payment.CardNumber.StartsWith("0000"))
179+
{
180+
// Simulate a card decline for test purposes
181+
throw new PaymentException("Card declined");
182+
}
183+
// Otherwise, pretend the charge succeeded
184+
}
185+
}
186+
public class ShippingService
187+
{
188+
public void ScheduleShipment(Order order)
189+
{
190+
// Dummy implementation: in reality would call a shipping API
191+
if (string.IsNullOrWhiteSpace(order.ShippingAddress))
192+
{
193+
throw new Exception("Invalid shipping address");
194+
}
195+
// Simulate success (no return value needed)
196+
}
197+
}
198+
public class NotificationService
199+
{
200+
public void SendOrderConfirmation(string email, string orderId)
201+
{
202+
// Dummy implementation: in reality would send an email
203+
if (string.IsNullOrWhiteSpace(email) || !email.Contains("@"))
204+
{
205+
throw new Exception("Invalid email address");
206+
}
207+
// Simulate success (e.g., email sent)
208+
}
209+
}
210+
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
5+
namespace LogProcessing;
6+
7+
public class LogAnalyzer
8+
{
9+
public void AnalyzeLogs(string[] logFiles)
10+
{
11+
// Step 1: File I/O Setup (open files, prepare to read)
12+
if (logFiles == null || logFiles.Length == 0)
13+
{
14+
Console.WriteLine("No log files specified. Exiting.");
15+
return;
16+
}
17+
int totalLines = 0;
18+
double totalResponseTime = 0.0;
19+
var errorTypeCounts = new Dictionary<string, int>();
20+
21+
foreach (string filePath in logFiles)
22+
{
23+
if (string.IsNullOrWhiteSpace(filePath))
24+
{
25+
Console.WriteLine("Skipped an empty file path.");
26+
continue;
27+
}
28+
try
29+
{
30+
using var reader = new StreamReader(filePath);
31+
string line;
32+
while ((line = reader.ReadLine()) != null)
33+
{
34+
totalLines++;
35+
// Step 2: Parsing and Filtering
36+
// Assume log format: Date|Level|Message|...|Duration (fields separated by '|')
37+
string[] parts = line.Split('|');
38+
if (parts.Length < 3)
39+
{
40+
// Skip lines that don't have the expected format
41+
continue;
42+
}
43+
string level = parts[1].Trim(); // e.g., "INFO" or "ERROR"
44+
string message = parts[2].Trim();
45+
// Filter: focus on ERROR level entries for error stats
46+
if (level.Equals("ERROR", StringComparison.OrdinalIgnoreCase))
47+
{
48+
// Determine a simple error category from the message content
49+
string errCategory;
50+
if (message.Contains("NullReference")) errCategory = "NullReferenceException";
51+
else if (message.Contains("OutOfMemory")) errCategory = "OutOfMemoryError";
52+
else errCategory = "GeneralError";
53+
if (errorTypeCounts.ContainsKey(errCategory))
54+
errorTypeCounts[errCategory]++;
55+
else
56+
errorTypeCounts[errCategory] = 1;
57+
}
58+
// Step 3: Aggregation (accumulate response time if present)
59+
if (parts.Length >= 5)
60+
{
61+
string durationStr = parts[4].Trim();
62+
if (double.TryParse(durationStr, out double duration))
63+
{
64+
totalResponseTime += duration;
65+
}
66+
// If parsing fails, ignore that line's duration
67+
}
68+
}
69+
}
70+
catch (FileNotFoundException)
71+
{
72+
Console.WriteLine($"Error: Log file not found -> {filePath}");
73+
continue;
74+
}
75+
catch (UnauthorizedAccessException)
76+
{
77+
Console.WriteLine($"Error: Access denied to log file -> {filePath}");
78+
continue;
79+
}
80+
catch (IOException ex)
81+
{
82+
Console.WriteLine($"Error reading file {filePath}: {ex.Message}");
83+
continue;
84+
}
85+
}
86+
87+
// Step 4: Output/Reporting
88+
Console.WriteLine("=== Log Analysis Summary ===");
89+
Console.WriteLine($"Total Lines Processed: {totalLines}");
90+
if (totalLines > 0)
91+
{
92+
double avgResponseTime = totalResponseTime / totalLines;
93+
Console.WriteLine($"Average Response Time: {avgResponseTime:F3}");
94+
}
95+
else
96+
{
97+
Console.WriteLine("Average Response Time: N/A (no lines processed)");
98+
}
99+
Console.WriteLine("Error Type Counts:");
100+
if (errorTypeCounts.Count > 0)
101+
{
102+
foreach (var kv in errorTypeCounts)
103+
{
104+
Console.WriteLine($" {kv.Key}: {kv.Value}");
105+
}
106+
}
107+
else
108+
{
109+
Console.WriteLine(" (No errors encountered)");
110+
}
111+
}
112+
}
113+
114+
// A simple Program class to demonstrate usage of LogAnalyzer
115+
public class Program
116+
{
117+
public static void Main(string[] args)
118+
{
119+
var analyzer = new LogAnalyzer();
120+
analyzer.AnalyzeLogs(args);
121+
// Usage: pass log file paths as command-line arguments.
122+
// E.g., `dotnet run logs\\app.log logs\\db.log`
123+
}
124+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>

0 commit comments

Comments
 (0)