Category: .NET

[NuGet]: Transplator

This is a Nuget that it is what Razor should have been. It is a Roslyn Source Code Generator that transforms template into code.

Link: https://www.nuget.org/packages/Transplator 

Site: https://github.com/atifaziz/Transplator

What it does:  Takes a template and generates source code for outputting anything inside.

Usage:

Somewhere in the csproj:

<ItemGroup>
   <CompilerVisibleProperty Include=”DebugTransplator” />
   <CompilerVisibleItemMetadata Include=”AdditionalFiles” MetadataName=”SourceItemType” />
   <CompilerVisibleItemMetadata Include=”AdditionalFiles” MetadataName=”Name” />
   <AdditionalFiles Include=”ASM.txt” SourceItemType=”Transplate” KeepMetadata=”Name” />

</ItemGroup>

Somewhere in a .cs file

var response = new ASMTemplate().Render();

And the template

partial class ASMTemplate
{
     StringBuilder sb = new StringBuilder();
     public void WriteText(string text)
     {
         sb.AppendLine(text);
     }
     public void WriteValue(int text)
     {
         sb.AppendLine(“”+text);
     }  
     public void WriteValue(int? text)
     {
         if(text != null)
             sb.AppendLine(“” + text);
     }
     public void WriteValue(DateTime text)
     {
         sb.AppendLine(text.ToString(“yyyy MMMM dd HH:mm:ss”));
     }
     public void WriteValue(string text)
     {
         sb.AppendLine(text);
     }
     public string Render()
     {        
         this.RenderCore();
         return sb.ToString();
     }
}

RSCG Example – Tiny Types – Part 23

 

 

name BaseTypes
nuget

https://www.nuget.org/packages/AndreasDorfer.BaseTypes/

link https://github.com/Andreas-Dorfer/base-types
author Andreas Dorfer

Generated tiny types from any value type
 

The code that you start with is


    [Int] public partial record DepartmentId;

    public Employee GetFromId(int idDepartment, int idEmployee)

    {

        

        return new Employee()

        {

            ID = idEmployee,

            DepartmentId = idDepartment,

            Name = "Andrei " + idEmployee

    

        };

    }

    public Employee GetFromId(DepartmentId departmentId,  EmployeeId employeeId)

    {

        return GetFromId(departmentId, employeeId);

    }


The code that you will use is



    e.GetFromId(10, 34);

    e.GetFromId(new DepartmentId(34), new EmployeeId(10));

 

The code that is generated is


    [System.ComponentModel.TypeConverter(typeof(AD.BaseTypes.Converters.BaseTypeTypeConverter<DepartmentId, int>))]

    [System.Text.Json.Serialization.JsonConverter(typeof(AD.BaseTypes.Json.BaseTypeJsonConverter<DepartmentId, int>))]

    sealed partial record DepartmentId : System.IComparable<DepartmentId>, System.IComparable, AD.BaseTypes.IBaseType<int>

    {

        public DepartmentId(int value)

        {

            this.Value = value;

        }

        public int Value { get; }

        public override string ToString() => Value.ToString();

        public int CompareTo(object? obj) => CompareTo(obj as DepartmentId);

        public int CompareTo(DepartmentId? other) => other is null ? 1 : System.Collections.Generic.Comparer<int>.Default.Compare(Value, other.Value);

        public static implicit operator int(DepartmentId item) => item.Value;

        public static DepartmentId Create(int value) => new(value);

    }

Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/TinyTypes

All RSCG

NrBlog Post
1RSCG–part 1
2RSCG- AppVersion–part 2
3http://msprogrammer.serviciipeweb.ro/2021/02/17/rsgc-enum-part-3/
4RSGC-JSON to Class- part 4
5RSGC-Constructor – Deconstructor – part 5
6RSGC – DTO Mapper – part 6
7RSGC – Skinny Controllers- part 7
8RSGC-Builder Design Pattern – part 8
9RSGC- MetadataFromObject – part 9
10RSGC- Dynamic Mock – part 10
11RSCG- Method Decorator – part 11
12RSCG – Curry – Partial function – part 12
13RSCG- part 13 – IFormattable
14RSCG- part 14 – DP_Decorator
15RSCG- part 15 – Expression Generator
16RSCG- part 16 – Many Others
17RSCG- the book
18RSCG–Template Rendering- part 17
19CI Version
20HttpClientGenerator
21Query from database
22AutoRegister
23TinyTypes
24Static2Interface
25AppSettings
26Properties
27
Roslyn Source Code Generators

RecordVisitors- BDD–part 9

It is recommended to have tests. And better is to  see the output of the tests in some readable format .

On other hand, I do not like full BDD   frameworks as SpecFlow – I think that are too overkill in order to achieve less.

So – something like https://github.com/LightBDD/LightBDD seems to fit the bill.

After you read the documentation, it is not so difficult. You transform test from

[Fact]
public async void TestFakeUser()
{

    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.GetStringAsync("/recordVisitors/AllVisitors5Min");

    // Assert
    var str = "JeanIrvine";
    Assert.True(response.Contains(str), $"{response} must contain {str}");

}


into

HttpClient client;
string response;
private void Given_The_Application_Starts()
{
  StepExecution.Current.Comment("!!!Start application!!!!");
  client = _factory.CreateClient();
}

private async Task When_The_User_Access_The_Url(string url)
{
    response = await client.GetStringAsync(url);
}
private void Then_The_Response_Should_Contain(string str)
{            
    Assert.True(response.Contains(str), $"{response} must contain {str}");
}

[Scenario]
[ScenarioCategory("VisitorRecord")]
public async void TestFakeUser()
{
    await Runner
        .AddSteps(Given_The_Application_Starts)
        .AddAsyncSteps(
            _ => When_The_User_Access_The_Url("/recordVisitors/AllVisitors5Min")
        )
        .AddSteps(
            _ => Then_The_Response_Should_Contain("JeanIrvine")

        )
        .RunAsync();
                
}


Yes, it seems some more code – but you can re-use the functions and , more, the documentation looks great!

The results can bee seen at https://record-visitors.readthedocs.io/en/latest/BDD/LightBDDReport/

AutoActions for Skinny controllers–custom template

Now I want to let the user make his own template. For this, I have enriched the attribute AutoActionsAttribute with a

public string CustomTemplateFileName { get; set; }

 

The code was pretty easy, just reading from GeneratorExecutionContext . AdditionalFiles instead of reading from the template in the dll

 

switch (templateId)
{

case TemplateIndicator.None:
	context.ReportDiagnostic(DoDiagnostic(DiagnosticSeverity.Info, $"class {myController.Name} has no template "));
	continue;
case TemplateIndicator.CustomTemplateFile:

	var file = context.AdditionalFiles.FirstOrDefault(it => it.Path.EndsWith(templateCustom));
	if (file == null)
	{
		context.ReportDiagnostic(DoDiagnostic(DiagnosticSeverity.Error, $"cannot find {templateCustom} for  {myController.Name} . Did you put in AdditionalFiles in csproj ?"));
		continue;
	}
	post = file.GetText().ToString();
	break;

default:
	using (var stream = executing.GetManifestResourceStream($"SkinnyControllersGenerator.templates.{templateId}.txt"))
	{
		using var reader = new StreamReader(stream);
		post = reader.ReadToEnd();

	}
	break;
}

 

There are 2 small catches

1 see the EndsWith  ? The GeneratorExecutionContext . AdditionalFiles  gives you the full path

2. the additional files should be registered in the .csproj

<ItemGroup>
<AdditionalFiles Include=”Controllers\CustomTemplate1.txt” />
</ItemGroup>

 

Now the user can define his own template for the controller like this


[AutoActions(template = TemplateIndicator.CustomTemplateFile, FieldsName = new[] { "*" } ,CustomTemplateFileName = "Controllers\\CustomTemplate1.txt")]
    [Route("api/[controller]/[action]")]
    [ApiController]
    public partial class CustomTemplateController : ControllerBase
    {
        private readonly RepositoryWF repository;

        public CustomTemplateController ()
        {
            //do via DI
            repository = new RepositoryWF();
        }

    }

And this is all ! ( ok. some documentation should be involved)

[ADCES] Presentation about .NET 5

My presentation were about EFCore, RoslynGenerators, Breaking Changes and ClickOnce.

Code and presentation at https://ignatandrei.github.io/Presentations/NET5prez.html .

Next presentation will be

De la Multinationala la Startup & Filbo – Technical Stack

Tuesday, Jan 12, 2021, 7:30 PM

Online event
,

19 Members Attending

Prezentare 1 : De la multinationala la startup si freelancer – sau cum sa iti parasesti cariera bine platita pentru alta Speaker: Daniel Tila, https://automationpill.com/ Descriere: Aventurile unui programator in cautarea businessului Prezentare 2: Filbo – Technical Stack Speaker: Adrian Nasui, https://www.linkedin.com/in/adrian-nasui-b887a5a9/…

Check out this Meetup →

[ADCES].NET 5 What’s new and awesome

Daniel Costea , Andrei Ignat si Dan Patrascu-Baba si o sa faca demo practice despre

1. C# – What’s new

2. ASP.NET Core – What’s new

3. EF Core – What’s new

4. Auto-Update de aplicatii Asp.NET Core si WPF prin ClickOnce

5. Roslyn Generators pentru code

6. Breaking changes

7 What’s new in Blazor on .NET 5?

Speaker: Dan Patrascu-Baba, http://danpatrascu.com/

Description: .NET 5 is probably one of the most important milestones in the history of .NET. Everybody is excited about the new release and we have plenty of reasons to be as a bunch o new features and improvements have been announced. In this talk we’ll dive deeper in the new Blazor features released with .NET 5, both for Blazor Server and Blazor WebAssembly. We’ll tackle concepts like CSS and JS isolation, lazy loading, secure local storage interactions and much more.

Va astept la https://www.meetup.com/Bucharest-A-D-C-E-S-Meetup/events/273633735/ !
( Acest eveniment este in colaborare cu .NET Romania )

SideCarCLI–looking at past and at future

Summary links SideCarCLI

NoName + Link 
1Description
2Specifications
3Refactor specifications and code
4Create Release
5Finish interceptors
6Send part of command to interceptors
7Line Interceptors
8Finish process after some time
9Documetation Diagram
10Technical Summary
11Create dotnet tool
( Description : SideCar for CLI applications. Interceptors for Line, Finish, Timer . See Code )

It was interesting to develop the project for command line same as for cloud design pattern, https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar .

The problem were more about

  1. architecture
  2. organizing features to be easy understandable
  3. , testing the application
  4. writing about

 

rather than  technical, about how to make the application.

Other , it was a pretty simple project , that can be useful in  CI / CD operations.

It remains :

Make a dot net tool –  https://github.com/ignatandrei/SideCarCLI/issues/10

Compiling as Windows and Linux https://github.com/ignatandrei/SideCarCLI/issues/11

Make documentation with use case – https://github.com/ignatandrei/SideCarCLI/issues/12

Make Tests  https://github.com/ignatandrei/SideCarCLI/issues/13

Fun with Moniker- naming assembly versions

I liked the way docker generates names for every container instance – it was a funny way to differentiate them. I was thinking  – what about nuget packages – or any other release  ?

I have discovered Moniker – https://github.com/alexmg/Moniker . Can be used as in docker – to generate different names at various runs. However, what I wanted is to make every release to have a funny name.

I have put in .NET Core local tools ( see https://youtu.be/iHLRBxi4S7c  and the blog post http://msprogrammer.serviciipeweb.ro/2020/06/08/net-core-local-tools/ ) and I have used from powershell ( see https://github.com/ignatandrei/NETCoreBlockly/ for the usage)

First, I have created a variable

if($result -eq 0){

$moniker = “$(dotnet moniker -s moby)-$dateToPrint”

}

else{

$moniker = “$(dotnet moniker -s moniker)-$dateToPrint”

}

then used this variable in the release notes

$releaseNotes += (“;BuildNumber $env:BUILD_BUILDNUMBER with name “+ $moniker)

and in assembly title

dotnet-property “**/*.csproj” AssemblyTitle:”NetCoreBlockly $moniker”

Then, in C# , I write in the console:

static string nameBlockly()

{

var ass = Assembly.GetExecutingAssembly();

var assName = ass.GetName();

var nameBlockly = assName.Name;

try

{

var title = ass.GetCustomAttribute<AssemblyTitleAttribute>();

nameBlockly = title?.Title ?? nameBlockly;

}

catch

{

//do nothing

}

return $”{nameBlockly} version:{assName.Version.ToString()}”;

}

If you want to see in action , you can:

  1. Look at the nuget release notes at https://www.nuget.org/packages/NetCore2Blockly/ ( see BuildNumber … with name
  2. See the change log https://github.com/ignatandrei/NETCoreBlockly/blob/master/changelog.md – every release has the name
  3. Install NetCoreBlockly  and see the name 

Exchange rates–what I have done in 37 hours–part 38

What I have create for now in 37 hours :

  1. A source control – https://github.com/ignatandrei/InfoValutar
  2. A plugin based software – you can use to load any kind of exchange rates, for anywhere , provided that you implement the interface – see implementation
  3. Tests for some of the code
  4. Deployment:
  5. A SqlServer database – to store datas
  6. An Azure Function  – https://azurefuncloaddata20191205080713.azurewebsites.net/ –  to load data at time based cron intervals
  7. A GitHub action to compile ,run tests , – https://github.com/ignatandrei/InfoValutar/actions
  8. An AzureDevops CI + CD  to do all 1-6 things +code coverage + deploy https://dev.azure.com/ignatandrei0674/InfoValutar/_build?definitionId=5&_a=summary

 

I did say it is a nice work for 37 hours of work, right ?

Infovalutar

And one hour passes...
(This is the result of 1 hour per day auto-challenge as a full cycle developer for an exchange rates application)
( You can see the sources at https://github.com/ignatandrei/InfoValutar/ )
NrPost 
1Start
2Reading NBR from internet
3Source control and build
4Badge and test
5CI and action
6Artifacts and dotnet try
7Docker with .NET Try
8ECB
9Intermezzo - Various implementations for programmers
10Intermezzo - similar code - options
11Plugin implementation
12GUI for console
13WebAPI
14Plugin in .NET Core 3
15Build and Versioning
16Add swagger
17Docker - first part
18Docker - second part
19Docker - build Azure
20Pipeline send to Docker Hub
21Play with Docker - online
22Run VSCode and Docker
23Deploy Azure
24VSCode see tests and powershell
25Code Coverage
26Database in Azure
27Sql In Memory or Azure
28Azure ConString, RSS
29Middleware for backward compatibility
30Identical Tables in EFCore
31Multiple Data in EFCore
32Dot net try again
33Start Azure Function
34Azure function - deploy
35Solving my problems
36IAsyncEnumerable transformed to IEnumerable and making Azure Functions works
37Azure functions - final
38Review of 37 hours
39Last Commit in AzureDevOps
40Create Angular WebSite
41Add static Angular to WebAPI .NET Core
42Docker for Angular
43Angular and CORS
44SSL , VSCode, Docker
45Routing in Angular
46RxJS for Routing
47RxJs Unsubscribe

C# WebAPI and NotFound with message in MVC .NET 4.5

Usually, WEBAPI should return correct HTML status code ( read also https://damienfremont.com/2017/11/23/rest-api-maturity-levels-from-0-to-5/ ) . Let’s say we are saving an entity  – the OK result could return a meaningful message. How about querying for an id that you cannot find ? Easy: NotFound :  .But –the NotFound does NOT show an message. How a client can make a difference between the fact that the entity is not found for a specific id and the fact that ,maybe, the whole site is not deployed / a route does not exists  ? What we need is a NotFound with a specific message. ( In .NET Core we have NotFoundObjectResult )

I have found 2 solutions: one complicated and one simple.

The complicated one:

var err = Request.CreateErrorResponse(
HttpStatusCode.NotFound,
new HttpError("my message”)
);
return new ResponseMessageResult(err);

The simple one

//this is for APIController only, not usual controller in .NET 4.5
return Content(HttpStatusCode.NotFound, "my message");

Enjoy!

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.