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

Port to .NET core #358

Closed
mookid8000 opened this issue Nov 9, 2015 · 77 comments
Closed

Port to .NET core #358

mookid8000 opened this issue Nov 9, 2015 · 77 comments
Assignees
Milestone

Comments

@mookid8000
Copy link
Member

No description provided.

@mookid8000
Copy link
Member Author

@mookid8000
Copy link
Member Author

@mookid8000
Copy link
Member Author

@gertjvr
Copy link
Contributor

gertjvr commented Feb 12, 2016

I was able to run rebus + rabbitmq with mono inside docker container :)

@mookid8000
Copy link
Member Author

Cool! and that just worked?

@gertjvr
Copy link
Contributor

gertjvr commented Feb 12, 2016

Yip serilog was broken but got around it with the beta packages
On 12 Feb 2016 6:50 PM, "Mogens Heller Grabe" notifications@github.com
wrote:

Cool! and that just worked?


Reply to this email directly or view it on GitHub
#358 (comment).

@runes83
Copy link

runes83 commented Apr 6, 2016

Is this something you are working on?
Could open up many new possiblities :-)

@mookid8000
Copy link
Member Author

I'm currently watching the .NET Core progress, waiting for things to settle down just a bit before I do too much.

So I'm not actively working on it, but I am definitely planning on doing it :)

@imperugo
Copy link

Hi,
dunno if you already notice it (otherwise ignore my comment), but .NET Core is RTM now.

@mookid8000
Copy link
Member Author

Thanks for reminding me 😄 and yes, I did notice that - in fact I've installed it both on my Mac and in my Windows VM. My plan is to play around with releasing some of my smaller things on .NET Core first, e.g. Tababular and Injectionist

@NKnusperer
Copy link
Contributor

Any updates on this?

@mookid8000
Copy link
Member Author

Not really – is it something you would find interesting?

@NKnusperer
Copy link
Contributor

No, currently not. But would be cool to see Rebus services running on Linux ^^

@gertjvr
Copy link
Contributor

gertjvr commented Aug 17, 2016

Looking pretty close to having all dependencies there to port to .net core https://icanhasdot.net/result?github=rebus-org~2Frebus

@bertvansteen
Copy link

As a DevOps enthousiast I think the release of NET Core is awesome, I'm playing with .NET Core, Docker and NGINX in a pet project and absolutely love it.

Don't underestimate the effort that will go into supporting .NET Core: I hacked together a PoC version of Rebus that supports .NET Standard 1.5 with RabbitMQ and StructureMap, it's nothing near finished and didn't even run the unit tests:

https://github.com/bertvansteen/Rebus/tree/netcore-rabbitmq-structuremap-poc

Some notes:

  • .NET Standard 1.5 is supported by .NET core and .NET 4.6;
  • The easiest way to convert a project to a .NET standard library is to rename the folder, add a new .NET core library project and copy all files into the new project;
  • MSMQ is a windows only product and there is no .NET standard package available, I disabled all this code with a compiler precondition #if FULL_NET (I know I should have used the official preconditions described in https://docs.microsoft.com/en-us/dotnet/articles/core/tutorials/libraries but remember that this is a hack);
  • I couldn't find a .NET Standard alternative for SQL Server's DbConnectionProvider so I disabled it;
  • AsyncLocal is an alternative for CallContext
  • ApplicationException is not available;
  • The timer used by Rebus is not available, you'll have to use another one;
  • Filesystem.Lock is not available, I just disabled it;
  • StringComparer.InvariantCultureIgnoreCase is not available, and I blindly changed it to StringComparer.OrdinalIgnoreCase;
  • Reflection is available but requires an additional GetTypeInfo() method
  • ConfigurationManager.ConnectionStrings is not available in .NET standard but is used for looking up the SQL Server connection string, I didn't search for the alternative;
  • NUnit test won't show up in the test explorer but I didn't troubleshooted the issue.
  • I'm referencing the convertetd project in my pet project so I didn't bother fixing the Nuget packages yet.
  • Encoding.HeaderName is not available, Encoding.WebName at least works for UTF8

I hope this helps in better understanding the effort required for supporting .NET Core.

@mookid8000
Copy link
Member Author

@bertvansteen thank you so much for reporting your experiences 👍

I don't understand fully how these things work yet.... I know .NETStandard 1.1 corresponds to .NET 4.5... are the .NETStandard targets backwards compatible, such that it would be possible to target .NETStandard 1.1 and thus support all newer platforms?

@bertvansteen
Copy link

bertvansteen commented Aug 18, 2016

This is an experiment for me too.

It appears that most of the compiler errors disappear when targetting .NET Standard 1.5 (supported in .NET 4.6.2 and .NET core) which is a superset of 1.4 which in turn is a superset... We have to target multiple frameworks and use compiler directives to support .NET 4.5, I've updated my PoC branch, I also fixed the unit testing discovery issue for .NET 4.5. (but autodata doesn't work yet)

You might want to consider removing the MSMQ transport and SQL Server persistance from the core project and move it to a separate assembly like RabbitMQ or Redis because commenting out a large chunk of code with compiler directives is not the way to go. Both versions of Rebus should more or less contain the same features and it might take a while before Microsoft releases a .NET Standard compatible version of the MSMQ connector since it's a Windows only product.

Some more notes:

@mookid8000
Copy link
Member Author

I have been messing around a little bit with these things. Rebus has not been split into separate repositories, which was a prerequisite in order to be able to commence porting the code to .NET Core.

As far as I can tell, it will be valid to use the following approach:

  • Replace current Rebus core project with one based on the new project.json/xproj format (or whatever comes in the future 😁 )
  • Use the multi-targeting functionality to target the following two:
    1. .NET 4.5/CLR4 in order to support all full .NET frameworks 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, and 4.6.2 in the easiest possible way
    2. .NET Core/CoreCLR
  • Disable unsupported things and dodge unsupported APIs with compile-time directives (#ifdef/#ifndef SOMETHING_APROPRIATE #endif)

I have tried to port the code to the project.json/xproj format, but I stalled at the fact that ReSharper could not run my tests. I will probably have another go at it soon, maybe just running the tests from the command line. Or maybe experimenting with keeping the csproj around as well – as far as I can tell, project.json and xproj can be created and need not be modified unless packages are installed/uninstalled etc.

@mookid8000 mookid8000 added this to the Rebus 3 milestone Dec 11, 2016
@mvandevy
Copy link
Contributor

Been playing with the conversion of Rebus to .net core as well on my fork ([https://github.com/mvandevy/Rebus]) and been able to get it working as expected. All unit tests run green after some initial bug hunting. Probably made some suboptimal choices along the way, but wanted to get it running & testable. I've used the suggestions made by @bertvansteen to have an initial PoC running. What are there any plans to start the making the libraries .net core compatible?

@mookid8000
Copy link
Member Author

mookid8000 commented Dec 15, 2016

well.... I'm not sure I have thought it through yet – but I was thinking of making it .NET Core compatible and then call it "Rebus 3"....

but I guess that is not even necessary – it should be possible to compile a Rebus 2.2.0 even (the 2.1.6 version is the most recent on NuGet.org), simply adding a "lib/DNXORWHATEVERITISCALLEDTHESEDAYS" folder in addition to the existing "lib/NET45" folder in the NuGet package, right?

@mookid8000
Copy link
Member Author

Probably made some suboptimal choices along the way, but wanted to get it running & testable

That's a huge step btw., so that is just awesome!

@mookid8000
Copy link
Member Author

From the project.json it does not seem like you are targeting .NET 4.5 too – is there something I am missing?

@mvandevy
Copy link
Contributor

You are right, I'm not yet targeting .NET 4.5. Thats the next step, just wanted to make sure that it worked on .net core first. Maybe you've already tried converting it and keeping it compatible with .NET 4.5. If that's the case, then I've missed that change/issue where you did something similar and mentioned it.

Anyway, by your response it seems I have some more work ahead before you'll accept a pull request ;-)

@mookid8000
Copy link
Member Author

Anyway, by your response it seems I have some more work ahead before you'll accept a pull request ;-)

well..... I would love a PR, but I don't want to obstruct the current line of development with Rebus.... I will accept your PR anytime, but I would like to keep it on a separate branch for now.

Just let me know when you feel like contributing it – then I will set up the branch 😄

@mvandevy
Copy link
Contributor

I'll let you know when I have something decent to put into a branch. Hopefully rather sooner than later.

One of the most prominent breaking changes on .net core is the disappearance of the 'ApplicationException' base class. That caused me a headache at first while running the tests, especially in the 'TestRetryExceptionCustomization' test as I used the 'Exception' class as a replacement for the 'ApplicationException' class.

I've also the tests to Xunit, because didn't have the time yet to play around with NUnit on .net core. One thing to mention about this, is that the test suite doesn't really like to be executed in a parallel mode ;-)

@mookid8000
Copy link
Member Author

I'll let you know when I have something decent to put into a branch. Hopefully rather sooner than later.

🤘

One of the most prominent breaking changes on .net core is the disappearance of the 'ApplicationException' base class. That caused me a headache at first while running the tests, especially in the 'TestRetryExceptionCustomization' test as I used the 'Exception' class as a replacement for the 'ApplicationException' class.

I actually thought I had replaced all usage of ApplicationException with RebusApplicationException... 😳

I've also the tests to Xunit, because didn't have the time yet to play around with NUnit on .net core. One thing to mention about this, is that the test suite doesn't really like to be executed in a parallel mode ;-)

ah, bummer – but aren't almost all of the tests running on the in-mem transport?

do you know if there is a way to create "mutual exclusion groups" of tests, or somehow affect what gets to run in parallel and what needs to be serialized?

@mookid8000
Copy link
Member Author

Thanks to @mvandevy 's persistence and hard work, I have now adapted build scripts and stuff and figured out how to release this betaversion of Rebus that targets .NET 4.5 and .NET Core (in the form of netstandard1.6).

Check this out:

image

I have done the same things to Rebus.Serilog, Rebus.SqlServer, Rebus.RabbitMq, and Rebus.Autofac, so it should actually be possible now to get an endpoint up and running with all areas covered.

Thanks @mvandevy for kicking me until I could no longer ignore you 🤜 😁

@mvandevy
Copy link
Contributor

Great news! Thanks for the effort of getting it published!

@mookid8000
Copy link
Member Author

mookid8000 commented Mar 21, 2017

I'll keep track of the status here:

  • Rebus 🏅
  • Rebus.AmazonSQS 🏅
  • Rebus.Async 🏖
  • Rebus.Autofac 🏅
  • Rebus.AutoScaling 🏖
  • Rebus.AzureServiceBus 😞 – look at amqpnetlite instead, maybe?
  • Rebus.AzureStorage 🏅
  • Rebus.CastleWindsor 😞
  • Rebus.DryIoc 🥇
  • Rebus.Events 🏖
  • Rebus.Jil 🏅
  • ~~~Rebus.LegacyCompatibility~~~
  • Rebus.LightInject 🏅
  • Rebus.Log4net 🏅
  • Rebus.MongoDb 🏅
  • Rebus.MsgPack 😞
  • Rebus.Msmq 😐
  • Rebus.Ninject 🏅
  • Rebus.NLog 🏅
  • Rebus.Owin
  • Rebus.PostgreSql 🏅
  • Rebus.Protobuf 🏅
  • Rebus.RabbitMq 🏅
  • Rebus.RavenDb 🏅
  • ~~~Rebus.Recipes~~~
  • Rebus.Serilog 🏅
  • Rebus.ServiceProvider 🏅
  • Rebus.SimpleInjector 🏅
  • Rebus.SqlServer 🏅
  • Rebus.StructureMap 🏅
  • Rebus.TransactionScopes
  • Rebus.UnitOfWork 🏖
  • Rebus.Unity 😞
  • ~~~Rebus.WindowsHost~~~ 😐
  • Rebus.Wire 🏅
  • Rebus.XmlConfig 😐

🏖 : means that the package has no dependencies
🏅 : means that the dependencies support .NET Core
😞 : means that the dependencies do NOT not support .NET Core
😐 : means that it probably doesn't make sense to port the package to .NET Core
––––– means that the project is to be considered deprecated

@mookid8000
Copy link
Member Author

If anyone plays around with the new 4.0.0-b?? versions, it would be awesome if you would post your experiences here.... I am interested in hearing about full .NET framework experiences just as well as .NET Core experiences.

@danielmarbach
Copy link

The ASB Team is working on a .NET core compliant SDK. https://github.com/Azure/azure-service-bus-dotnet it is just a question of how long it takes ;)

@mookid8000
Copy link
Member Author

mookid8000 commented Mar 27, 2017

Here's the steps I go through when porting a project:

0. Don't open the solution file

Using Visual Studio 2017, control yourself and refrain from opening up the .sln. We will manually edit some files first, using a real text editor like e.g. Sublime.

1. Edit appveyor.yml

Take appveyor.yml from a project that has already been ported (e.g. Rebus.DryIoc) and adapt it to build the package's main and test projects.

Look out for required services: and be sure they are brought over too.

2. Edit <main-project>.csproj

Open it up in a text editor and copy over the csproj contents from a project that has already been ported. Fix the 3-4 places where the project name occurs. Remove any unneeded NuGet PackageReference elements carried over.

3. Edit <test-project>.csproj

Same procedure as when porting the main project, only using e.g. Rebus.DryIoc's test project as source.

4. Copy over the updated scripts

Copy over the four files in the /scripts folder from e.g. Rebus.DryIoc. Just overwrite the existing scripts.

The scripts are there to be invoked by Bob.

5. Finally: Open the solution in VS2017

Iterate like this:

  • Try compiling the whole thing
  • Add missing NuGet packages
  • Fix code that cannot be compiled (using #if NETSTANDARD1_6/#if NET45 directives – if it's a lot, please add a Shims.cs or similar, where extension methods can be placed and the preprocessor directives can then be kept)

VS2017, or Resharper 2017.1 EAP 5, or both in combination, are buggy as hell, and you may need to close the solution and open it again for some changes to take effect. Especially when adding new NuGet imports or new source files, weird stuff can happen, and the solution is almost always to simply reopen the solution.

6. Send PR 💌

@mvandevy
Copy link
Contributor

BTW, would anyone be interested in a Rebus.MySql project which is also .net standard compatible? Just happened to have this lying around. 😁

@mookid8000
Copy link
Member Author

I don't have that need myself, but I think it would be a pretty cool addition!

@mvandevy
Copy link
Contributor

OK, let me clean it up a little so I can point you to it. Or would you want to create a repo for this, with the basic stuff in it, so I can create a pull request?

@mookid8000
Copy link
Member Author

I'll create the repo – this way, you can send a PR and have your name all over it 😄

@mookid8000
Copy link
Member Author

@mvandevy I've pushed my boilerplate here

@mookid8000
Copy link
Member Author

ALL projects have now been ported to the new project structure, and those whose dependencies do not prevent it are targeting .NET Standard 1.6 in addition to the usual .NET 4.5 (or in some cases 4.5.1 / 4.5.2)

The core Rebus package is out in version 4.0.0-b10, and all the most recent versions of the other packages depend on this particular version.

All packages are out in prerelease versions. It would be awesome if someone would check it out, no matter if they're on .NET Core or on the full .NET framework.

🤗

@BredStik
Copy link

Great work to all of those involved!

@debabrata-das
Copy link

Azure Service Bus is now available for .Net Core.
Do you know when Rebus.AzureServiceBus will support it also??

@mookid8000
Copy link
Member Author

🤘

soon! (as in: one of the following days)

@danielmarbach
Copy link

danielmarbach commented Aug 15, 2017 via email

@mookid8000
Copy link
Member Author

Ah, thanks for warning me – it'll be interesting to see how much of the API surface I am currently using can be translated directly to the new driver.

@theoriginalkien
Copy link

hi @mookid8000, any expected date on a release of Rebus.AzureServiceBus that support .net core?

@mookid8000
Copy link
Member Author

Unfortunately, it turned out that the new driver implementation had been changed radically, compared to the old driver, especially with regards to receiving messages.

I think I will get some time next week where I can see if I can make something work.

@hulvei3
Copy link

hulvei3 commented Sep 11, 2017

@mookid8000 thank you for this awesome work on getting Rebus onto supporting .NET Core. It's a bummer with Rebus.AzureServiceBus though, but we can already use it as is right now, at least on windows.
It would be great in time to be able to this lib to the full extend of .Net Core.

@bhaidar
Copy link

bhaidar commented Aug 13, 2018

Any updates on the status of Rebus? Can we use it in ASP.NET Core 2.1? Thanks

@mookid8000
Copy link
Member Author

Yes, Rebus has supported .NET Core since March 2017 😄

Rebus 4 is built targeting .NET 4.5 and .NET Standard 1.3, and Rebus 5 will add .NET Standard 2 as a target too.

@bhaidar
Copy link

bhaidar commented Aug 13, 2018

@mookid8000
Thanks a lot.

Im new to this and I am bit confused about Rebus.

Is it just a bus? I see, there is Rebus.AzureServiceBus, Rebus.RabbitMq, Rebus.AzureStorage, Rebus.PostgreSql, and other packages? What's the deal here, what is exactly Rebus and why having all those packages?

I am switching to CQRS now.

Thanks

@mookid8000
Copy link
Member Author

Is it just a bus? (...) What's the deal here, what is exactly Rebus and why having all those packages?

Rebus provides implementations of common messaging patterns like request/reply, publish/subscriber, correlation ID, process manager, dead-letter queues, claim check, etc.

It does so in a way that makes your code portable across transports, so you can e.g. start out by configuring it to work with RabbitMQ. Later, if you need to move your system to the cloud, you can configure it to use Azure Service Bus. Or Amazon SQS.

In addition to this, it makes coding event-driven applications pleasant, because its APIs are quire simple and approachable 😄

If you are curious to read about Rebus, I suggest you go look at the wiki – it has explanations for most concepts.

If you want to see code that uses Rebus, you can check out the RebusSamples repository

@bhaidar
Copy link

bhaidar commented Aug 13, 2018

That's an amazing explanation @mookid8000
Indeed, looks very promising!

I am reading and learning CQRS, DDD and such patterns nowadays and want to apply those concepts to a real-life app.

There are many micro frameworks out there on Github that can handle messaging, etc. That's why the options are many :-)

When you say request/reply, does that correspond to commands? Typically, when you execute a command, you need an answer to the client (accepted or not at least).

As for publishing/subscriber, it reminds me more of handling Domain Events and Event Sourcing? Or am I talking about something else?

What about the event store? Does Rebus support that? Because with event sourcing you need the event store to persist the events, etc.

Process Manager, are we talking about a "Saga"?

I will for sure check out the wiki and the samples!

Thanks

@mookid8000
Copy link
Member Author

When you say request/reply, does that correspond to commands? Typically, when you execute a command, you need an answer to the client (accepted or not at least).

Yes, it's typically a command where the sender is somehow interested in the result. In code it could look like this (at the client's end and the "Inventory Service"'s end, respectively):

// at the client end:
await bus.Send(new MakeInventoryAllocation(...));

// and then in the "Inventory Service":
await bus.Reply(new MakeInventoryAllocationReply(
    success: couldMakeInventoryAllocation,
    correlationId: correlationIdFromCommand
));

As for publishing/subscriber, it reminds me more of handling Domain Events and Event Sourcing? Or am I talking about something else?

If you work with event sourcing, you typically need stronger ordering guarantees than what a library like Rebus can provide (because it runs on message queues and often will process messages in parallel, either by multiple threads or even in multiple processes).

What about the event store? Does Rebus support that? Because with event sourcing you need the event store to persist the events, etc.

No 😄 Rebus runs on message queues. You could of course model a message queue on top of an event store, but if you want to use a real event store, it's probably more fun to code your app such that it takes advantage of all of the extra guarantees that it provides.

Process Manager, are we talking about a "Saga"?

Yes 😄 it's called "Saga" because Rebus started out as a copy of the functionality I liked from NServiceBus, so that word stuck. It's called a "Process Manager" in the literature though, so I usually use that word. Also, "Sagas" usually imply you use some kind of compensating actions for steps that fail or otherwise cannot be completed, but that's in no way required with Rebus.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests