OpenRIAServices / OpenRiaServices

The Open RIA Services project continues what was previously known as WCF RIA Services.
https://openriaservices.gitbook.io/openriaservices/
Apache License 2.0
54 stars 47 forks source link

Duplicate CodeGen Bug when building more than once #505

Open FabioSilvaOS opened 1 month ago

FabioSilvaOS commented 1 month ago

Describe the bug With the attached projects (RiaBug.zip), the SERVER project builds correctly, and the CLIENT projects build correctly, and correctly creates the generated files the FIRS TIME. For C#, the 2nd time we got a warning, and from 3rd time we do not have problems. But with VB.Net, the second time we got errors and the projects does not build anymore. You can try in Visual Studio, but to avoid IDE quirks I tested in command line. just go to desired project folder and execute dotnet build. After the problem arises (for VB.Net), the only one way to build again is performing dotnet clean and then dotnet build. But when you build again the problem returns.

Summary: For C#

  1. First time it builds correctly;
  2. Second time I receive a warning: warning CS2002: Source file 'C:\tmp\RiaBug\CS\CsClient\Generated_Code\CsServer.g.cs' specified multiple times
  3. Third time and on: Builds correctly;

For VB:

  1. First time it builds correctly;
  2. From second time, the project will not build anymore. I receive multiple errors regarding duplicate members:
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(53,16): error BC30269: 'Public Sub New()' has multiple definitions with identical signatures. [C:\t
    mp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(65,45): error BC30269: 'Public Shared ReadOnly Property Current As WebContext' has multiple definit
    ions with identical signatures. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(95,20): error BC30269: 'Public Sub New()' has multiple definitions with identical signatures. [C:\t
    mp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(103,20): error BC30269: 'Public Sub New(serviceUri As Uri)' has multiple definitions with identical
    signatures. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(111,20): error BC30269: 'Public Sub New(domainClient As DomainClient)' has multiple definitions wit
    h identical signatures. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(122,35): error BC30269: 'Public Overloads Function WhatTimeIsIt(callback As Action(Of InvokeOperati
    on(Of Date)), userState As Object) As InvokeOperation(Of Date)' has multiple definitions with identical signatures. [C:\tmp\RiaBug\VB\VbClient\VbClient.vb
    proj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(131,35): error BC30269: 'Public Overloads Function WhatTimeIsIt() As InvokeOperation(Of Date)' has
    multiple definitions with identical signatures. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(141,25): error BC30269: 'Public Function WhatTimeIsItAsync([cancellationToken As CancellationToken
    = Nothing]) As Task(Of InvokeResult(Of Date))' has multiple definitions with identical signatures. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(150,38): error BC30269: 'Protected Overrides Function CreateEntityContainer() As EntityContainer' h
    as multiple definitions with identical signatures. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(158,26): error BC30179: interface 'IClockServiceContract' and interface 'IClockServiceContract' con
    flict in class 'VbServer.RiaBug.ClockContext'. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(178,37): error BC30179: class 'ClockContextEntityContainer' and class 'ClockContextEntityContainer'
    conflict in class 'VbServer.RiaBug.ClockContext'. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(86,29): error BC31433: Method 'OnCreated' cannot be declared 'Partial' because only one method 'OnC
    reated' can be marked 'Partial'. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(44,25): error BC31433: Method 'OnCreated' cannot be declared 'Partial' because only one method 'OnC
    reated' can be marked 'Partial'. [C:\tmp\RiaBug\VB\VbClient\VbClient.vbproj]
    C:\tmp\RiaBug\VB\VbClient\Generated_Code\VbServer.g.vb(157,10): error BC30663: Attribute 'ServiceContractAttribute' cannot be applied multiple times. [C:\
    tmp\RiaBug\VB\VbClient\VbClient.vbproj]

To Reproduce I added this repro in zip, but it is very very simple, I saw that problems in a big project, and then I created a MRE to test RiaBug.zip

The server project file (same for vbproj and csproj):

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

<ItemGroup>
    <PackageReference Include="OpenRiaServices.Hosting.AspNetCore" Version="1.1.0" />
    <PackageReference Include="OpenRiaServices.Server" Version="5.4.3" />
</ItemGroup>

</Project>

The server Program.cs file:

using OpenRiaServices.Hosting.AspNetCore;
using OpenRiaServices.Server;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenRiaServices();
builder.Services.AddTransient<RiaBug.ClockService>();

var app = builder.Build();

app.MapGet("/", () => "Hello OpenRia!");

app.MapOpenRiaServices(builder =>
{
    builder.AddDomainService<RiaBug.ClockService>();
});

app.Run();

namespace RiaBug
{
    [EnableClientAccess]
    public class ClockService : DomainService
    {
            [Invoke()]
            public DateTime WhatTimeIsIt()
            {
                return DateTime.Now;
            }
    }
}

The server Program.vb file:

Imports Microsoft.AspNetCore.Builder
Imports Microsoft.Extensions.DependencyInjection
Imports OpenRiaServices.Hosting.AspNetCore
Imports OpenRiaServices.Server

Module Program
    Sub Main(args As String())

        Dim builder = WebApplication.CreateBuilder(args)

        builder.Services.AddOpenRiaServices()
        builder.Services.AddTransient(Of RiaBug.ClockService)()

        Dim app = builder.Build()

        app.MapGet("/", Function() "Hello OpenRia!")

        app.MapOpenRiaServices(Sub(b) b.AddDomainService(Of RiaBug.ClockService)())

        app.Run()
    End Sub
End Module

Namespace RiaBug

    <EnableClientAccess>
    Public Class ClockService 
        Inherits DomainService

            <Invoke()>
            Public Function WhatTimeIsIt() As DateTime
                Return DateTime.Now
            End Function

    End Class
End Namespace

The client just need the proj file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <RootNamespace></RootNamespace>
    <LinkedOpenRiaServerProject>..\CsServer\CsServer.csproj</LinkedOpenRiaServerProject>
    <OpenRiaGenerateApplicationContext>true</OpenRiaGenerateApplicationContext>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="OpenRiaServices.Client.CodeGen" Version="5.4.3">
        <PrivateAssets>all</PrivateAssets>
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="OpenRiaServices.Client.Core" Version="5.4.3" />
  </ItemGroup>

</Project>

Expected behavior Every time the client project needs to build correctly

Nuget package and version

EDIT The same happens if I use OpenRiaServices.Client instead of OpenRiaServices.Client.Core + OpenRiaServices.Client.CodeGen

FabioSilvaOS commented 1 month ago

For the record, I'm not sure if this is a fix or a workaround, but I found if I put in client proj file:

<EnableDefaultCompileItems>false</EnableDefaultCompileItems>

this bug disappears.

Daniel-Svensson commented 1 month ago

I had hoped that the bug bug had been resolved in #229 where the includes are configured to remove duplciates, previously I often did something similar to below in order to avoid the problem , it might work for you

From "AspNetCore.Client.CodeGen.csproj" sample project:

    <ItemGroup>
        <Compile Remove="Generated_Code\AspNetCore.Hosting.AspNetCore.g.cs" />
        <None Include="Generated_Code\AspNetCore.Hosting.AspNetCore.g.cs" />
    </ItemGroup>

Or just add disable EnableDefaultCompileItems and add <Compile Include="**/*.cs" Exclude="Generated_Code/**;obj/**;bin/**" />

If you have any suggestion of how this could be fixed in https://github.com/OpenRIAServices/OpenRiaServices/blob/main/src/OpenRiaServices.Tools/Framework/build/OpenRiaServices.Client.CodeGen.targets feel free to create a PR

FabioSilvaOS commented 1 month ago

@Daniel-Svensson I checked output build logs, and I think maybe it could not remove duplicates because, for example, one item is pointing to Generated_Code\CsServer.g.cs and other is pointing to C:\tmp\RiaBug\CS\CsClient\Generated_Code\CsServer.g.cs same file, but one path is relative and other absolute.

I will try check for a solution, but I need to finish my deadlines first and, for now, EnableDefaultCompileItems was enough :smile:.

Daniel-Svensson commented 1 month ago

That sounds promising. It should hopefully be solvable by converting/normalizing the paths from the openriaservices task between full and relative paths (so they match default item includes).

I think I have seen such functionality built into msbuild.

Good luck with the deadline and in the meantime, the workaround is documented here.

Daniel-Svensson commented 3 weeks ago

Note:

It is possible to make paths from openria code generation relative either in code or using https://learn.microsoft.com/en-us/visualstudio/msbuild/property-functions?view=vs-2022#msbuild-makerelative