Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v5.8.0 #234

Merged
merged 5 commits into from
Jan 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

Represents the **NuGet** versions.

## v5.8.0
- *Fixed:* Upgraded `CoreEx` (`v3.8.0`) to include all related fixes and improvements; `WebApi` class supports returning value of `IActionResult` as-is.
- *Enhancement:* Updated code-generation to support `IActionResult` return type for `WebApi` operations. The following `operation` YAML properties enable:
- New `webApiProduces: [ 'text/plain' ]` where the value is a `Produces` content type array (supports multiple) to override the default; for example `[Produces("text/plain")]`.
- New `webApiProducesResponseType: none` indicates that the resulting generated code does _not_ include the response type; for example `[ProducesResponseType((int)HttpStatusCode.OK)]`.

## v5.7.4
- *Fixed:* Upgraded `CoreEx` (`v3.7.2`) to include all related fixes and improvements; updated reference data code-generation template and samples as a result.

Expand Down
2 changes: 1 addition & 1 deletion Common.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>5.7.4</Version>
<Version>5.8.0</Version>
<LangVersion>preview</LangVersion>
<Authors>Avanade</Authors>
<Company>Avanade</Company>
Expand Down
4 changes: 3 additions & 1 deletion docs/Entity-Operation-Config.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Property | Description
**`name`** | The unique operation name. [Mandatory]
**`type`** | The type of operation that is to be code-generated. Valid options are: `Get`, `GetColl`, `Create`, `Update`, `Patch`, `Delete`, `Custom`.<br/>&dagger; Defaults to `Custom`.
`text` | The text for use in comments.<br/>&dagger; The `Text` will be defaulted for all the `Operation.Type` options with the exception of `Custom`. To create a `<see cref="XXX"/>` within use moustache shorthand (e.g. {{Xxx}}).
**`primaryKey`** | Indicates whether the properties marked as a primary key (`Property.PrimaryKey`) are to be used as the parameters.<br/>&dagger; This simplifies the specification of these properties versus having to declare each specifically.
**`primaryKey`** | Indicates whether the properties marked as a primary key (`Property.PrimaryKey`) are to be used as the parameters.<br/>&dagger; This simplifies the specification of these properties as parameters versus having to declare each specifically. Each of the parameters will also be set to be mandatory.
**`paging`** | Indicates whether a `PagingArgs` argument is to be added to the operation to enable (standardized) paging related logic.
`valueType` | The .NET value parameter `Type` for the operation.<br/>&dagger; Defaults to the parent `Entity.Name` where the `Operation.Type` options are `Create` or `Update`.
`returnType` | The .NET return `Type` for the operation.<br/>&dagger; Defaults to the parent `Entity.Name` where the `Operation.Type` options are `Get`, `GetColl`, `Create` or `Update`; otherwise, defaults to `void`.
Expand Down Expand Up @@ -112,6 +112,8 @@ Property | Description
`webApiConcurrency` | Indicates whether the Web API is responsible for managing (simulating) concurrency via auto-generated ETag.<br/>&dagger; This provides an alternative where the underlying data source does not natively support optimistic concurrency (native support should always be leveraged as a priority). Where the `Operation.Type` is `Update` or `Patch`, the request ETag will be matched against the response for a corresponding `Get` operation to verify no changes have been made prior to updating. For this to function correctly the .NET response Type for the `Get` must be the same as that returned from the corresponding `Create`, `Update` and `Patch` (where applicable) as the generated ETag is a SHA256 hash of the resulting JSON. Defaults to `Entity.WebApiConcurrency`.
`webApiGetOperation` | The corresponding `Get` method name (in the `XxxManager`) where the `Operation.Type` is `Update` and `SimulateConcurrency` is `true`.<br/>&dagger; Defaults to `Get`. Specify either just the method name (e.g. `OperationName`) or, interface and method name (e.g. `IXxxManager.OperationName`) to be invoked where in a different `YyyManager.OperationName`.
`webApiUpdateOperation` | The corresponding `Update` method name (in the `XxxManager`) where the `Operation.Type` is `Patch`.<br/>&dagger; Defaults to `Update`. Specify either just the method name (e.g. `OperationName`) or, interface and method name (e.g. `IXxxManager.OperationName`) to be invoked where in a different `YyyManager.OperationName`.
`webApiProduces` | The value(s) for the optional `[Produces()]` attribute for the operation within the Web Api Controller for the Swagger/OpenAPI documentation.
`webApiProducesResponseType` | The `[ProducesResponseType()]` attribute `typeof` for the operation within the Web Api Controller for the Swagger/OpenAPI documentation.<br/>&dagger; Defaults to the _Common_ type. A value of `None`, `none` or `` will ensure no type is emitted.

<br/>

Expand Down
2 changes: 1 addition & 1 deletion samples/Cdr.Banking/Cdr.Banking.Api/Cdr.Banking.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>true</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CoreEx.AspNetCore" Version="3.7.2" />
<PackageReference Include="CoreEx.AspNetCore" Version="3.8.1" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,16 @@ public Task<IActionResult> GetDetail(string? accountId)
[ProducesResponseType((int)HttpStatusCode.NotFound)]
public Task<IActionResult> GetBalance(string? accountId)
=> _webApi.GetWithResultAsync<Balance?>(Request, p => _manager.GetBalanceAsync(accountId));

/// <summary>
/// Get <see cref="Account"/> statement (file).
/// </summary>
/// <param name="accountId">The <see cref="Account"/> identifier.</param>
/// <returns>A resultant <see cref="FileContentResult"/>.</returns>
[HttpGet("api/v1/banking/accounts/{accountId}/statement")]
[Produces("text/plain")]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
public Task<IActionResult> GetStatement(string? accountId)
=> _webApi.GetWithResultAsync<FileContentResult?>(Request, p => _manager.GetStatementAsync(accountId), alternateStatusCode: HttpStatusCode.NoContent, operationType: CoreEx.OperationType.Unspecified);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
<Folder Include="DataSvc\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CoreEx.Cosmos" Version="3.7.2" />
<PackageReference Include="CoreEx.Validation" Version="3.7.2" />
<PackageReference Include="CoreEx.AspNetCore" Version="3.8.1" />
<PackageReference Include="CoreEx.Cosmos" Version="3.8.1" />
<PackageReference Include="CoreEx.Validation" Version="3.8.1" />
</ItemGroup>
</Project>
8 changes: 8 additions & 0 deletions samples/Cdr.Banking/Cdr.Banking.Business/Data/AccountData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Azure.Cosmos.Linq;
using System.Text;

namespace Cdr.Banking.Business.Data;

Expand Down Expand Up @@ -48,4 +49,11 @@ partial void AccountDataCtor()
return bal.Adjust(b => b.Id = a.Id);
});
}

/// <summary>
/// Gets the statement (file) for the specified account.
/// </summary>
private Task<Result<FileContentResult?>> GetStatementOnImplementationAsync(string? accountId)
=> Result.GoAsync(GetDetailAsync(accountId))
.WhenAs(d => d is not null, d => new FileContentResult(Encoding.UTF8.GetBytes($"Statement for Account '{d.AccountNumber}'."), "text/plain") { FileDownloadName = $"{accountId}.statement.txt" });
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public Task<Result<AccountCollectionResult>> GetAccountsAsync(AccountArgs? args,
/// <inheritdoc/>
public Task<Result<Balance?>> GetBalanceAsync(string? accountId) => GetBalanceOnImplementationAsync(accountId);

/// <inheritdoc/>
public Task<Result<FileContentResult?>> GetStatementAsync(string? accountId) => GetStatementOnImplementationAsync(accountId);

/// <summary>
/// Provides the <see cref="Account"/> to Entity Framework <see cref="Model.Account"/> mapping.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,11 @@ public partial interface IAccountData
/// <param name="accountId">The <see cref="Account"/> identifier.</param>
/// <returns>The selected <see cref="Balance"/> where found.</returns>
Task<Result<Balance?>> GetBalanceAsync(string? accountId);

/// <summary>
/// Get <see cref="Account"/> statement (file).
/// </summary>
/// <param name="accountId">The <see cref="Account"/> identifier.</param>
/// <returns>A resultant <see cref="FileContentResult"/>.</returns>
Task<Result<FileContentResult?>> GetStatementAsync(string? accountId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ public AccountDataSvc(IAccountData data, IRequestCache cache)

/// <inheritdoc/>
public Task<Result<Balance?>> GetBalanceAsync(string? accountId) => Result.Go().CacheGetOrAddAsync(_cache, accountId, () => _data.GetBalanceAsync(accountId));

/// <inheritdoc/>
public Task<Result<FileContentResult?>> GetStatementAsync(string? accountId) => _data.GetStatementAsync(accountId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,11 @@ public partial interface IAccountDataSvc
/// <param name="accountId">The <see cref="Account"/> identifier.</param>
/// <returns>The selected <see cref="Balance"/> where found.</returns>
Task<Result<Balance?>> GetBalanceAsync(string? accountId);

/// <summary>
/// Get <see cref="Account"/> statement (file).
/// </summary>
/// <param name="accountId">The <see cref="Account"/> identifier.</param>
/// <returns>A resultant <see cref="FileContentResult"/>.</returns>
Task<Result<FileContentResult?>> GetStatementAsync(string? accountId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,11 @@ public Task<Result<AccountCollectionResult>> GetAccountsAsync(AccountArgs? args,
return Result.Go().Requires(accountId)
.ThenAsAsync(() => _dataService.GetBalanceAsync(accountId));
}, InvokerArgs.Read);

/// <inheritdoc/>
public Task<Result<FileContentResult?>> GetStatementAsync(string? accountId) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) =>
{
return Result.Go().Requires(accountId)
.ThenAsAsync(() => _dataService.GetStatementAsync(accountId));
}, InvokerArgs.Unspecified);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,11 @@ public partial interface IAccountManager
/// <param name="accountId">The <see cref="Account"/> identifier.</param>
/// <returns>The selected <see cref="Balance"/> where found.</returns>
Task<Result<Balance?>> GetBalanceAsync(string? accountId);

/// <summary>
/// Get <see cref="Account"/> statement (file).
/// </summary>
/// <param name="accountId">The <see cref="Account"/> identifier.</param>
/// <returns>A resultant <see cref="FileContentResult"/>.</returns>
Task<Result<FileContentResult?>> GetStatementAsync(string? accountId);
}
1 change: 1 addition & 0 deletions samples/Cdr.Banking/Cdr.Banking.Business/GlobalUsings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
global using CoreEx.Results;
global using CoreEx.Validation;
global using CoreEx.Validation.Rules;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.Logging;
global using System;
Expand Down
10 changes: 9 additions & 1 deletion samples/Cdr.Banking/Cdr.Banking.CodeGen/entity.beef-5.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,15 @@ entities:
# Route requires accountId; e.g. api/v1/banking/accounts/{accountId}/balance
# Data access logic cannot be auto-implemented.
#
{ name: GetBalance, text: 'Get {{Account}} {{Balance}}', type: Get, returnType: Balance, webApiRoute: '{accountId}/balance', primaryKey: true, autoImplement: None }
{ name: GetBalance, text: 'Get {{Account}} {{Balance}}', type: Get, returnType: Balance, webApiRoute: '{accountId}/balance', primaryKey: true, autoImplement: None },
# Operation to get an Account statement _file_.
# Operation is 'Custom' to specifically override and manually implement data.
# ReturnType of FileContentResult (standard ASP.NET) is an IActionResult which will be returned as-is.
# PrimaryKey="true" indicates that all properties marked as PrimaryKey are to be used for parameters (avoids having to explicitly define again).
# WebApiProducesResponseType="none" indicates that the [ProducesResponseType()] attribute should not include the response type (also ensures that the Agent code does not include response type).
# WebApiProduces enables specification of the [Produces()] attribute and corresponding value(s) array.
#
{ name: GetStatement, text: 'Get {{Account}} statement (file)', type: Custom, primaryKey: true, returnType: FileContentResult?, webApiMethod: HttpGet, webApiRoute: '{accountId}/statement', webApiProducesResponseType: none, webApiProduces: [ text/plain ] }
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,9 @@ public Task<HttpResult<AccountCollectionResult>> GetAccountsAsync(AccountArgs? a
/// <inheritdoc/>
public Task<HttpResult<Balance?>> GetBalanceAsync(string? accountId, HttpRequestOptions? requestOptions = null, CancellationToken cancellationToken = default)
=> GetAsync<Balance?>("api/v1/banking/accounts/{accountId}/balance", requestOptions: requestOptions, args: HttpArgs.Create(new HttpArg<string?>("accountId", accountId)), cancellationToken: cancellationToken);

/// <inheritdoc/>
public Task<HttpResult> GetStatementAsync(string? accountId, HttpRequestOptions? requestOptions = null, CancellationToken cancellationToken = default)
=> GetAsync("api/v1/banking/accounts/{accountId}/statement", requestOptions: requestOptions, args: HttpArgs.Create(new HttpArg<string?>("accountId", accountId)), cancellationToken: cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,14 @@ public partial interface IAccountAgent
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <returns>A <see cref="HttpResult"/>.</returns>
Task<HttpResult<Balance?>> GetBalanceAsync(string? accountId, HttpRequestOptions? requestOptions = null, CancellationToken cancellationToken = default);

/// <summary>
/// Get <see cref="Account"/> statement (file).
/// </summary>
/// <param name="accountId">The <see cref="Account"/> identifier.</param>
/// <param name="requestOptions">The optional <see cref="HttpRequestOptions"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <returns>A <see cref="HttpResult"/>.</returns>
Task<HttpResult> GetStatementAsync(string? accountId, HttpRequestOptions? requestOptions = null, CancellationToken cancellationToken = default);
}
}
Loading