Open Closed

ABP Studio Microservice Proxy Setup #7125


User avatar
0
hiltond created

Hello,

I am working on developing with the ABP Studio microservice template and have a few questions on expected setup for new microservices. I have generated a basic setup using the microservice template (EF Core, MVC, no mobile UI). I follow the add new microservice (EF Core) option here: I get this initial layout:

It doesn’t seem like these microservice templates have proxy support by default (C# or JS). I would like to add this functionality in but have been struggling with how it should be added and what is required for full functionality.

I suspect that we would want to add some dependencies or setup code to the MyServiceModule and MyServiceContractsModule that mimics the HttpApi and HttpApi.Client from the DDD services in the past. I couldn’t glean any information from the other services because they seem to rely on full DDD components through library references.

I was able to generate a static JS proxy but could not understand the correct auth flow it required to work against an authorized endpoint. I could not get the C# proxies to properly generate at all (static or dynamic.)

A few things I would like clarified:

-          What is the minimum implementation to enable proxies (C#, JS, static and dynamic) in the new microservice service template? (I would like to avoid using more project layers than what already exists, this defeats the purpose of using the simpler service template) -          What is required for the Web project to use both the C# proxy through MVC razor and the JS proxy through a web page directly? -          Is anything required for the gateway? -          What is required for proper auth flows using both proxies?

Thanks!

  • ABP Framework version: v8.1.1
  • UI Type: MVC
  • Database System: EF Core (SQL Server)
  • Tiered (for MVC) or Auth Server Separated (for Angular): Studio Microservice Template

14 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    What is the minimum implementation to enable proxies (C#, JS, static and dynamic) in the new microservice service template? (I would like to avoid using more project layers than what already exists, this defeats the purpose of using the simpler service template)

    You can generate JS&CSharp proxy in the Example.Web project.

    Update web's .csproj file to add:

    <ItemGroup>
        <EmbeddedResource Include="**\*generate-proxy.json" />
        <Content Remove="**\*generate-proxy.json" />
    </ItemGroup>
    

    Add Contract module to the Web project:

    Update your webgateway's route config.

    Generate static proxy file:

    abp generate-proxy -t csharp -m YourService --url YourServiceURL --without-contracts abp generate-proxy -t js -m YourService --url YourServiceURL

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Because ABP Studio is early preview version, and the document is not clear. We will improve it.

  • User Avatar
    0
    hiltond created

    Following the steps above when I try to generate the proxy I get: It gives the same result for a JS version as well.

    I had the same result with my real project I am developing also.

    To try a few extra things I also ran it with the module name as Example.MyService to no avail.

    I also tried to generate the proxy directly in the MyService project instead of Web. (Assuming this is wrong generally, but I tried it nonetheless)

    Running against the service directly without specifying the Module gave this error (Also guessing this is unimportant here and the running vs Web is what matters?) I also ran it from the Web directory and it gave the same basic error about not finding the file.

    PS C:\Source\Example\Example\apps\web\Example.Web> abp generate-proxy -t csharp  --url http://localhost:44315 --without-contracts
    ABP CLI 8.1.1
    Could not find a part of the path 'C:\Source\Example\Example\apps\web\Example.Web\ClientProxies\app-generate-proxy.json'.
    System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Source\Example\Example\apps\web\Example.Web\ClientProxies\app-generate-proxy.json'.
       at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
       at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
       at System.IO.StreamWriter..ctor(String path)
       at Volo.Abp.Cli.ServiceProxying.CSharp.CSharpServiceProxyGenerator.CreateJsonFile(GenerateProxyArgs args, ApplicationApiDescriptionModel applicationApiDescriptionModel) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\ServiceProxying\CSharp\CSharpServiceProxyGenerator.cs:line 166
       at Volo.Abp.Cli.ServiceProxying.CSharp.CSharpServiceProxyGenerator.GenerateProxyAsync(GenerateProxyArgs args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\ServiceProxying\CSharp\CSharpServiceProxyGenerator.cs:line 154
       at Volo.Abp.Cli.Commands.ProxyCommandBase`1.ExecuteAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\Commands\ProxyCommandBase.cs:line 57
       at Volo.Abp.Cli.CliService.RunInternalAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 173
       at Volo.Abp.Cli.CliService.RunAsync(String[] args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 80
    Unhandled exception. System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Source\Example\Example\apps\web\Example.Web\ClientProxies\app-generate-proxy.json'.
       at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
       at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
       at System.IO.StreamWriter..ctor(String path)
       at Volo.Abp.Cli.ServiceProxying.CSharp.CSharpServiceProxyGenerator.CreateJsonFile(GenerateProxyArgs args, ApplicationApiDescriptionModel applicationApiDescriptionModel) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\ServiceProxying\CSharp\CSharpServiceProxyGenerator.cs:line 166
       at Volo.Abp.Cli.ServiceProxying.CSharp.CSharpServiceProxyGenerator.GenerateProxyAsync(GenerateProxyArgs args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\ServiceProxying\CSharp\CSharpServiceProxyGenerator.cs:line 154
       at Volo.Abp.Cli.Commands.ProxyCommandBase`1.ExecuteAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\Commands\ProxyCommandBase.cs:line 57
       at Volo.Abp.Cli.CliService.RunInternalAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 173
       at Volo.Abp.Cli.CliService.RunAsync(String[] args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 80
       at Volo.Abp.Cli.Program.Main(String[] args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli\Volo\Abp\Cli\Program.cs:line 43
       at Volo.Abp.Cli.Program.<Main>(String[] args)
    
  • User Avatar
    0
    hiltond created

    Another thing that I noticed is that the new module does not show up in the API definition on the Gateway. It also does not show up under "app" here if that is potentially expected.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    You need to specify the service name for the module's API For example: https://github.com/abpframework/abp/blob/dev/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/IdentityUserController.cs#L10-L11

  • User Avatar
    0
    hiltond created

    After implementing those changes it fixed the issue with the module name being invalid when I run the proxy generation command, but it still has the other issue with not being able to find a specific file. I'm not sure where this file is supposed to come from or what is supposed to be generating it.

    PS C:\Source\Example\Example\apps\web\Example.Web> abp generate-proxy -t csharp -m MyService  --url http://localhost:44315 --without-contracts     
    ABP CLI 8.1.1
    Could not find a part of the path 'C:\Source\Example\Example\apps\web\Example.Web\ClientProxies\MyService-generate-proxy.json'.
    System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Source\Example\Example\apps\web\Example.Web\ClientProxies\MyService-generate-proxy.json'.
       at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)        
       at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
       at System.IO.StreamWriter..ctor(String path)
       at Volo.Abp.Cli.ServiceProxying.CSharp.CSharpServiceProxyGenerator.CreateJsonFile(GenerateProxyArgs args, ApplicationApiDescriptionModel applicationApiDescriptionModel) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\ServiceProxying\CSharp\CSharpServiceProxyGenerator.cs:line 166
       at Volo.Abp.Cli.ServiceProxying.CSharp.CSharpServiceProxyGenerator.GenerateProxyAsync(GenerateProxyArgs args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\ServiceProxying\CSharp\CSharpServiceProxyGenerator.cs:line 154
       at Volo.Abp.Cli.Commands.ProxyCommandBase`1.ExecuteAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\Commands\ProxyCommandBase.cs:line 57
       at Volo.Abp.Cli.CliService.RunInternalAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 173
       at Volo.Abp.Cli.CliService.RunAsync(String[] args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 80
    Unhandled exception. System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Source\Example\Example\apps\web\Example.Web\ClientProxies\MyService-generate-proxy.json'.
       at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)        
       at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
       at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
       at System.IO.StreamWriter..ctor(String path)
       at Volo.Abp.Cli.ServiceProxying.CSharp.CSharpServiceProxyGenerator.CreateJsonFile(GenerateProxyArgs args, ApplicationApiDescriptionModel applicationApiDescriptionModel) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\ServiceProxying\CSharp\CSharpServiceProxyGenerator.cs:line 166
       at Volo.Abp.Cli.ServiceProxying.CSharp.CSharpServiceProxyGenerator.GenerateProxyAsync(GenerateProxyArgs args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\ServiceProxying\CSharp\CSharpServiceProxyGenerator.cs:line 154
       at Volo.Abp.Cli.Commands.ProxyCommandBase`1.ExecuteAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\Commands\ProxyCommandBase.cs:line 57
       at Volo.Abp.Cli.CliService.RunInternalAsync(CommandLineArgs commandLineArgs) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 173
       at Volo.Abp.Cli.CliService.RunAsync(String[] args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli.Core\Volo\Abp\Cli\CliService.cs:line 80
       at Volo.Abp.Cli.Program.Main(String[] args) in D:\ci\Jenkins\workspace\abp-volo-release\abp\framework\src\Volo.Abp.Cli\Volo\Abp\Cli\Program.cs:line 43   
       at Volo.Abp.Cli.Program.<Main>(String[] args)
    
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    I guess this is because the CLI has no permission to write files to C drive

  • User Avatar
    0
    hiltond created

    It seems like there is a bug with the CLI tool when generating the C# proxy. It's not able to create the ClientProxies folder as part of the generation command. I added that folder manually and it was able to generate the MyService-generate-proxy.json file.

    The Javascript proxy generates properly and creates the client-proxies folder in w wwroot without needing to manually add the folder.

    I added a couple tests to see if these function. I will show my added code below:

    services\MyService\Example.MyService\Controllers\DemoController.cs

    [Route("api/myservice/demo")]
    [RemoteService(Name = "MyService")]
    [Area("MyService")]
    public class DemoController : AbpController, IDemoAppService
    {
    	[HttpGet]
    	[Route("hello")]
    	public async Task<string> HelloWorld()
    	{
    		return await Task.FromResult("Hello World!");
    	}
    	
    	[HttpGet]
    	[Route("hello-authorized")]
    	[Authorize]
    	public async Task<string> HelloWorldAuthorized()
    	{
    		return await Task.FromResult("Hello World (Authorized)!");
    	}
    }
    

    services\MyService\Example.MyService.Contracts\Interfaces\IDemoAppService.cs

    public interface IDemoAppService : IApplicationService
        {
            Task<string> HelloWorld();
            Task<string> HelloWorldAuthorized();
        }
    

    apps\web\Example.Web\Pages\Index.cshtml.cs

    public class IndexModel : AbpPageModel
    {
    	private IDemoAppService _demoAppService;
    
    	public IndexModel(IDemoAppService demoAppService)
    	{
    		_demoAppService = demoAppService;
    	}
    	
    	public void OnGet()
    	{
    		var result = _demoAppService.HelloWorldAuthorized();
    		ViewData["HelloWorldAuthorized"] = result.Result;
    	}
    
    	public async Task OnPostLoginAsync()
    	{
    		await HttpContext.ChallengeAsync("oidc");
    	}
    }
    

    apps\web\Example.Web\Pages\Index.cshtml

    @page
    @model Example.Web.Pages.IndexModel
    @using Example.Web.Navigation
    @using Volo.Abp.AspNetCore.Mvc.UI.Layout
    @using Volo.Abp.Users
    @inject ICurrentUser CurrentUser
    @inject IPageLayout PageLayout
    @{
        PageLayout.Content.Title = "Welcome";
        PageLayout.Content.MenuItemName = ExampleMenus.Home;
    }
    @section scripts {
        <abp-script src="client-proxies/MyService-proxy.js" />
        
        <script>
            example.myService.controllers.demo.helloWorldAuthorized().then(function (result) {
                console.log(result);
            });
        </script>
    }
    <abp-card>
        <abp-card-body>
            <h2>
                About This Project
            </h2>
    
            <p>
                This is a startup template to build your own Microservice Solution on top of the <a href="https://commercial.abp.io/" target="_blank">ABP Commercial</a>.
            </p>
    
            <p>
                Hellow World OnGet
                <br />
                @ViewData["HelloWorldAuthorized"]
            </p>
    
            <hr/>
            <p class="text-end">
                <a href="https://commercial.abp.io?ref=tmpl" target="_blank">commercial.abp.io</a>
            </p>
        </abp-card-body>
    </abp-card>
    

    Running the project as detailed from above results in the Index page not being able to resolve the dependency for the C# client:

    If I remove the C# client test from the Index.html.cs to test the Javascript alone it cannot resolve the endpoint and returns a 404.

    I notice that it is targeting http://localhost:44357/ which is the Web project. Looking at the api/abp/api-definition endpoint shows that the MyService module is not being surfaced here.

    Not sure what I am missing at this point.

    I also noticed that you had a Bookstore example of this template you were referencing earlier. Is it possible to access a copy of that code so I can compare it directly against my code to see if there are any discrepancies?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Sorry.I missed a bit, you need to configure the static proxy.

    https://docs.abp.io/en/abp/latest/API/Static-CSharp-API-Clients#without-contracts-example

    context.Services.AddStaticHttpClientProxies(
        typeof(ContractsModule).Assembly
    );
    
  • User Avatar
    0
    hiltond created

    That definitely helped move it in the right direction. I am seeing the service show up in the api-definition now.

    However, when I target the endpoint through the proxy I get this error now:

    Here is the generated code it is targeting there:

    // This file is automatically generated by ABP framework to use MVC Controllers from CSharp
    using Example.MyService.Contracts.Interfaces;
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Volo.Abp;
    using Volo.Abp.Application.Dtos;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.Http.Client;
    using Volo.Abp.Http.Client.ClientProxying;
    using Volo.Abp.Http.Modeling;
    
    // ReSharper disable once CheckNamespace
    namespace Example.MyService.Controllers;
    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IDemoAppService), typeof(DemoClientProxy))]
    public partial class DemoClientProxy : ClientProxyBase<IDemoAppService>, IDemoAppService
    {
        public virtual async Task<string> HelloWorldAsync()
        {
            return await RequestAsync<string>(nameof(HelloWorldAsync));
        }
    
        public virtual async Task<string> HelloWorldAuthorizedAsync()
        {
            return await RequestAsync<string>(nameof(HelloWorldAuthorizedAsync));
        }
    }
    

    Let me know what you think, also if you want to see any specific files or configuration.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    I made a mistake.

    Try this:

    context.Services.AddStaticHttpClientProxies(
        typeof(ContractsModule).Assembly,
        "MyService"
    );
    
  • User Avatar
    0
    hiltond created

    Seeing the same error with that change.

    Is it possible to see the working Bookstore example of this?

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Could you share the example project with me? I will check it.

    My email is shiwei.liang@volosoft.com

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Config the static proxy in the Web module

Made with ❤️ on ABP v9.1.0-preview. Updated on November 11, 2024, 11:11