Add Module's Application project reference to  another solution's Application project.
And configure the module dependencies
[DependsOn(
    .....
    typeof(ModuleApplicationModule)
    )]
public class AnotherSolutionApplicationModule : AbpModule
{
}
Do the same thing above for other projects(Application.Contract , Domain , Domain.Shared, EntityFrameworkCore, HttpAPi, HttpApi.Client ...)
Config EntityFrameworkcore project
public class AnotherSolutionDbContext: ...
{
    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.ConfigureModule();
    }
}
                        can I modify it using a suite or not?
Of course, you can.
Because ABP Studio is early preview version, and the document is not clear. We will improve it.
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
Hi,
Could you please share a simple project to reproduce the problem? I will check it. shiwei.liang@volosoft.com
thanks
as for sharing a simple project hopefully i can send it later in the evening.
Ok, I'm waiting for this.
The last one, because is posible to use outbox pattern with no Sql database/context, so my last question is if i can configure the pattern to not delete the rows in AbpEventOutbox table after publishing on azure and mark as published instead of delete.
At the moment, it's not possible. If you don't remove it, it will cause performance problems as the data grows.
But you can consider to create a redundant table to back it up, and when data is deleted, insert the data into the redundant table
Hi,
For these purposes, you need to customize AzureDistributedEventBus
The first is the need to publish to different topics based on the event name of the Eto: The second is whether there's a way to override part of the message publishing with AzureDistributedEventBus to achieve the following: With the default implementation of the outbox pattern, when publishing the message to Azure Service Bus, override the message publishing to choose which topic the message corresponds to. Additionally, be able to, if the topic or subscription don't exist, create them programmatically using ServiceBusAdministrationClient.CreateTopicAsync from Azure.Messaging.ServiceBus.Administration.
ABP does not support posting to multiple topics, this is the code:
https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs#L70 https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs#L124 https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs#L287
You can override the AzureDistributedEventBus
Pseudo-code, I didn't test it, just provider an idea
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IDistributedEventBus), typeof(AzureDistributedEventBus), typeof(MyAzureDistributedEventBus))]
public class MyAzureDistributedEventBus : AzureDistributedEventBus, ISingletonDependency
{
    protected Dictionary<string, IAzureServiceBusMessageConsumer> Consumers { get; } = new();
    
    public MyAzureDistributedEventBus(
        IServiceScopeFactory serviceScopeFactory, 
        ICurrentTenant currentTenant,
        IUnitOfWorkManager unitOfWorkManager, 
        IOptions<AbpDistributedEventBusOptions> abpDistributedEventBusOptions,
        IGuidGenerator guidGenerator,
        IClock clock,
        IOptions<AbpAzureEventBusOptions> abpAzureEventBusOptions,
        IAzureServiceBusSerializer serializer,
        IAzureServiceBusMessageConsumerFactory messageConsumerFactory,
        IPublisherPool publisherPool,
        IEventHandlerInvoker eventHandlerInvoker,
        ILocalEventBus localEventBus,
        ICorrelationIdProvider correlationIdProvider) : base(
        serviceScopeFactory, 
        currentTenant, 
        unitOfWorkManager,
        abpDistributedEventBusOptions,
        guidGenerator, 
        clock, 
        abpAzureEventBusOptions,
        serializer,
        messageConsumerFactory,
        publisherPool,
        eventHandlerInvoker,
        localEventBus, 
        correlationIdProvider)
    {
    }
    protected async override Task PublishAsync(
        string eventName,
        byte[] body,
        string? correlationId,
        Guid? eventId)
    {
        var topicName = eventName;
        await CheckTopicAndConsumer(topicName);
        
        var message = new ServiceBusMessage(body) { Subject = eventName };
        if (message.MessageId.IsNullOrWhiteSpace())
        {
            message.MessageId = (eventId ?? GuidGenerator.Create()).ToString("N");
        }
        message.CorrelationId = correlationId;
        var publisher = await PublisherPool.GetAsync(
            topicName,
            Options.ConnectionName);
        await publisher.SendMessageAsync(message);
    }
    public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
    {
        var outgoingEventArray = outgoingEvents.ToArray();
        var eventGroup = outgoingEventArray.GroupBy(x => x.EventName);
        
        foreach (var events in eventGroup)
        {
            var topicName = events.Key;
            await CheckTopicAndConsumer(topicName);
            var publisher = await PublisherPool.GetAsync(
                topicName,
                Options.ConnectionName);
            using var messageBatch = await publisher.CreateMessageBatchAsync();
            foreach (var outgoingEvent in events)
            {
                var message = new ServiceBusMessage(outgoingEvent.EventData) { Subject = outgoingEvent.EventName };
                if (message.MessageId.IsNullOrWhiteSpace())
                {
                    message.MessageId = outgoingEvent.Id.ToString();
                }
                message.CorrelationId = outgoingEvent.GetCorrelationId();
                if (!messageBatch.TryAddMessage(message))
                {
                    throw new AbpException(
                        "The message is too large to fit in the batch. Set AbpEventBusBoxesOptions.OutboxWaitingEventMaxCount to reduce the number");
                }
                using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
                {
                    await TriggerDistributedEventSentAsync(new DistributedEventSent() {
                        Source = DistributedEventSource.Outbox,
                        EventName = outgoingEvent.EventName,
                        EventData = outgoingEvent.EventData
                    });
                }
            }
            await publisher.SendMessagesAsync(messageBatch);
        }
        
    }
    private  async Task CheckTopicAndConsumer(string eventName)
    {
        // check topic is exists
        // if not exists, create topic
        // ServiceBusAdministrationClient.CreateTopicAsync(eventName
        
        // check consumer is exists
        
        if(!Consumers.ContainsKey(eventName))
        {
            var consumer = MessageConsumerFactory.CreateMessageConsumer(
                eventName,
                Options.SubscriberName,
                Options.ConnectionName);
            consumer.OnMessageReceived(ProcessEventAsync);
            Consumers.Add(eventName, consumer);
        }
    }
    
    private async Task ProcessEventAsync(ServiceBusReceivedMessage message)
    {
        var eventName = message.Subject;
        if (eventName == null)
        {
            return;
        }
        var eventType = EventTypes.GetOrDefault(eventName);
        if (eventType == null)
        {
            return;
        }
        var eventData = Serializer.Deserialize(message.Body.ToArray(), eventType);
        if (await AddToInboxAsync(message.MessageId, eventName, eventType, eventData, message.CorrelationId))
        {
            return;
        }
        using (CorrelationIdProvider.Change(message.CorrelationId))
        {
            await TriggerHandlersDirectAsync(eventType, eventData);
        }
    }
}