QuellCode/CentronERP war nur als Gitlink (Submodul-Referenz auf 79c1142) getrackt, ohne .gitmodules und ohne erreichbares Remote. Der Untersuchungsgegenstand der Versuchsreihe war damit nicht reproduzierbar gesichert: Ein Klon haette ein leeres Verzeichnis erhalten, und die Belege der 3.287 Anforderungen waeren nicht ueberpruefbar gewesen. Umstellung: - Historie nach c:\DEV\CentronERP_git_snapshot_79c1142 ausgelagert (vollstaendig lesbar, enthaelt 79c1142 und Vorgaenger 89ccfd6) - Gitlink aus dem Index entfernt - Dateiinhalt aufgenommen: 24.557 Dateien, rund 333 MB Die verschachtelte .gitignore der Codebasis gilt weiter, Build-Artefakte bleiben ausgeschlossen. Details in Versuche/Versuch_01/_Codebasis-Nachweis.md
225 lines
6.3 KiB
Markdown
225 lines
6.3 KiB
Markdown
# Results and Responses in c-entron.NET
|
|
|
|
This document explains the `Result` and `Response` classes in c-entron.NET, their purpose, and how they interact across the system layers. These classes form a critical part of the error handling and communication pattern throughout the application.
|
|
|
|
## Overview
|
|
|
|
In c-entron.NET, we use a standardized approach for operation results and API responses:
|
|
|
|
1. **`Result`** - Internal class used within the business logic layer to indicate operation success/failure
|
|
2. **`Response`** - Web service API class that translates `Result` objects to client-friendly responses
|
|
|
|
This pattern provides:
|
|
- Consistent error handling across all application layers
|
|
- Type-safe return values with status information
|
|
- Clean separation between internal logic and API responses
|
|
- Standardized way to include error messages and codes
|
|
|
|
## Result Class
|
|
|
|
### Location
|
|
`src/backend/Centron.Interfaces/Results/Result.cs`
|
|
|
|
### Purpose
|
|
The `Result` class represents the outcome of an operation in the business logic layer. It includes not just the success/failure status, but also contextual information like error messages and exception details.
|
|
|
|
### Structure
|
|
|
|
```csharp
|
|
public class Result
|
|
{
|
|
public string Message { get; protected set; }
|
|
public int? MessageCode { get; protected set; }
|
|
public Exception Error { get; protected set; }
|
|
public ResultStatus Status { get; protected set; }
|
|
|
|
// Factory methods and constructors...
|
|
}
|
|
```
|
|
|
|
### Status Values
|
|
The `Result` object can have one of the following statuses:
|
|
|
|
- **Success** - The operation completed successfully
|
|
- **Error** - The operation failed due to an error
|
|
- **Warning** - The operation completed but with warnings
|
|
|
|
### Factory Methods
|
|
|
|
The `Result` class uses factory methods (instead of constructors) for creating result objects:
|
|
|
|
```csharp
|
|
// Success results
|
|
Result.AsSuccess();
|
|
Result.AsSuccess("Operation completed successfully");
|
|
|
|
// Error results
|
|
Result.AsError("The operation failed", messageCode: 100);
|
|
Result.AsError("Invalid input", error: exception);
|
|
|
|
// Warning results
|
|
Result.AsWarning("Some fields could not be processed");
|
|
|
|
// From exceptions
|
|
Result.FromException("Failed to process request", exception);
|
|
Result.FromException(exception);
|
|
```
|
|
|
|
### Generic Version
|
|
|
|
There is also a generic version `Result<T>` that carries data along with the status:
|
|
|
|
```csharp
|
|
// Success with data
|
|
Result<Customer> customerResult = Result<Customer>.AsSuccess(customer);
|
|
|
|
// Error with no data
|
|
Result<Customer> errorResult = Result<Customer>.AsError("Customer not found");
|
|
```
|
|
|
|
## Response Class
|
|
|
|
### Location
|
|
`src/webservice/Centron.WebServices.Core/Messages/Response.cs`
|
|
|
|
### Purpose
|
|
The `Response` class serves as the API response format returned by web services to clients. It translates the internal `Result` objects into standardized API responses.
|
|
|
|
### Structure
|
|
|
|
```csharp
|
|
[DataContract]
|
|
public class Response
|
|
{
|
|
[DataMember]
|
|
public StatusCode Status { get; set; }
|
|
|
|
[DataMember]
|
|
public string Message { get; set; }
|
|
|
|
[DataMember]
|
|
public int MessageCode { get; set; }
|
|
|
|
// Factory methods...
|
|
}
|
|
|
|
[DataContract]
|
|
public class Response<T> : Response
|
|
{
|
|
[DataMember]
|
|
public List<T> Result { get; set; }
|
|
|
|
// Additional factory methods...
|
|
}
|
|
```
|
|
|
|
### Status Values
|
|
The `Response` object can have one of the following statuses:
|
|
|
|
- **Success** - The operation completed successfully
|
|
- **Failed** - The operation failed due to an error
|
|
|
|
Note that unlike `Result`, `Response` maps both `ResultStatus.Success` and `ResultStatus.Warning` to `StatusCode.Success`.
|
|
|
|
## Interaction Between Result and Response
|
|
|
|
The key interaction occurs through the `FromBLResult` methods in the `Response` class:
|
|
|
|
```csharp
|
|
// Converting a Result to Response
|
|
Response response = Response.FromResult(result);
|
|
|
|
// Converting a Result<T> to Response<T>
|
|
Response<Customer> response = Response<Customer>.FromBLResult(customerResult);
|
|
```
|
|
|
|
### Mapping Logic
|
|
|
|
1. `Result.Status` is mapped to `Response.Status`:
|
|
- `ResultStatus.Success` → `StatusCode.Success`
|
|
- `ResultStatus.Warning` → `StatusCode.Success` (warnings are treated as success at API level)
|
|
- `ResultStatus.Error` → `StatusCode.Failed`
|
|
|
|
2. `Result.Message` is directly copied to `Response.Message`
|
|
|
|
3. `Result.MessageCode` is copied to `Response.MessageCode` (with a default if not provided)
|
|
|
|
4. For `Result<T>`, the data is added to the `Response<T>.Result` collection
|
|
|
|
## Usage Examples
|
|
|
|
### Business Logic Layer (BL)
|
|
|
|
```csharp
|
|
public Result<CustomerDTO> GetCustomerById(int customerId)
|
|
{
|
|
try
|
|
{
|
|
var customer = this._repository.GetCustomerById(customerId);
|
|
|
|
if (customer == null)
|
|
return Result<CustomerDTO>.AsError("Customer not found");
|
|
|
|
var dto = this.ConvertToDTO(customer);
|
|
return Result<CustomerDTO>.AsSuccess(dto);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result<CustomerDTO>.FromException(ex);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Web Service Layer
|
|
|
|
```csharp
|
|
public Response<CustomerDTO> GetCustomerById(int customerId)
|
|
{
|
|
var result = this._customerBL.GetCustomerById(customerId);
|
|
return Response<CustomerDTO>.FromBLResult(result);
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Always use factory methods** instead of constructors for creating `Result` objects
|
|
```csharp
|
|
// Good
|
|
return Result.AsSuccess("Operation succeeded");
|
|
|
|
// Avoid
|
|
return new Result(ResultStatus.Success, "Operation succeeded");
|
|
```
|
|
|
|
2. **Include meaningful error messages** to help diagnose issues
|
|
```csharp
|
|
// Good
|
|
return Result.AsError($"Customer with ID {id} not found");
|
|
|
|
// Avoid
|
|
return Result.AsError("Not found");
|
|
```
|
|
|
|
3. **Propagate exceptions appropriately** using `FromException`
|
|
```csharp
|
|
try
|
|
{
|
|
// Operation code
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result.FromException("Failed to complete operation", ex);
|
|
}
|
|
```
|
|
|
|
4. **Use `ThrowIfError` extension method** when chaining operations
|
|
```csharp
|
|
var result = await someOperation().ThrowIfError();
|
|
```
|
|
|
|
5. **Convert between `Result` and `Response` only at service boundaries** to maintain clean separation of concerns
|
|
|
|
## Conclusion
|
|
|
|
The `Result` and `Response` classes provide a robust pattern for error handling and operation results throughout the c-entron.NET application. Understanding how they work together is essential for maintaining consistency in API responses and proper error handling across all application layers.
|