ASPX pages are gone. I converted mine to static HTML files and replaced any dynamic elements with XHR callbacks. Existing XHR callbacks which previously were handled in Page_Load became handled by Controller/Routes I set up at the original ASPX url.

You can make "middleware". If you're familiar with Express for Node it works exactly the same way.

HttpException is gone. You can reimplement it yourself by making a custom Exception class and some middleware to try/catch it and produce the appropriate response to the client.

ApplicationException is gone, use Exception or make a blank ApplicationException class inheriting from it.

AppDomain is gone, unhandled/first chance exceptions can't be caught for now. You can try using a custom middleware to catch anything that happens during a request. GetExecutingAssembly is gone, use GetEntryAssembly, be careful if you're using this for the execution directory as it changes when you publish your project.

I redirected some ASPX urls to HTML using middleware (app.Use()) so bookmarks for the old site would still work.

TextWriterTraceListener is gone; I had used it for log file stuff. I could have replaced it fairly easy I guess since the base class is still there; instead I recoded my stuff to use the new logging system. You can inherit from a few classes and send logs anywhere.

ASMX files are gone, I haven't replaced mine yet but I would use a Controller/Route. You can probably fake the output to match ASMX if you have a legacy .NET Framework client consuming it or for backwards compatibility reasons.

I had to drop third-party libraries (was using one for PDF manipulation) and Web References. You can still use HttpClient if you want to manually call someone else's ASMX.

You can use Kestrel for a cross-platform ASP.NET server, built into .NET Core. It simplifies some things you can't really do with IIS, like figure out what ports your site is on (since your app is handling those directly now, Kestrel runs in-process I think).

You can finally get the local/remote addresses/ports of a request easily.

I had to do some weird stuff in .NET 4.5 to get a "persistent" connection to the client to stream data (ew, I know) without closing it. I had to rewrite it for .NET Core since the class I inherited from no longer existed. I rewrote it as a route and used a custom ActionResult that simply hung around forever and waited for other threads to call its functions to send out data. File() method on controllers now accepts a LOCAL URL (eg only files in the server's content root), where in .NET Framework it accepted an absolute local path. Use PhysicalFile() for that now.

There are now two ways to compile your app, with another way planned.

First way is the "normal" way, which generates a .NET DLL which you can run on any supported platform as long as you have the appropriate dotnet runtime on it.

Second is "standalone application" mode with effectively bundles the .NET runtime so you get a standalone application that doesn't need the runtime installed. However this build only runs for the platform you compile it on; cross-platform compilation is not yet supported. There are switches for it but if you use them you end up with a build for the current platform.

Planned for the future is native compilation which will produce a native platform build that doesn't need the runtime. This feature is not included in .NET Core 1.0 as it wasn't ready.

I had to adjust my connection string as .NET Core doesn't support the full array of stuff you can put in there. Notably, when running on Linux, I could not use a SQL Server Instance with SERVERNAME\INSTANCE; I had to specify the port number directly with SERVERNAME, PORT.

System.Drawing is gone as it wrapped Windows APIs. It will likely reappear later in the form of a library and not need a .NET Core update (since that is the whole point of all this).


A cross-platform server "Kestrel" is bundled into .NET. Unless you're using IIS on Windows you cannot identify requests by the requester's Windows account. This also means no impersonation of Windows accounts, though obviously that doesn't mean much on Linux/Mac anyway. web.config is no longer used to store settings since it is an IIS-specific thing. appsettings.json is now used for connection strings (a convention which you can break if you want) and it's up to you to store any legacy Settings somewhere else (not sure if appsettings.json can do it, I had my own settings file already for other stuff so I just merged them all in there).

Kestrel vs WebListener
 Choosing a server If you intend to deploy your application on a Windows server, you should prefer the Windows optimized servers (IIS and WebListener). IIS remains the best choice for typical web application deployments on Windows servers, and provides the richest set of features. Choose WebListener instead of IIS only if you need to host your application within your own process or service. Use Kestrel if you intend to develop on or deploy to non-Windows environments.

Routes and filters are now done differently, and controllers don't need to be specially named or in a specific namespace any more. I chose to use attributes on specific functions to define the routes that call those functions. For ASP.NET Core MVC we decided to adopt MVC 5.x's conventional routing approach and not Web API 2.x's approach. With the conventional routing approach, the route must specify both a controller and an action.