5

I am migrating a webform (not a WebForm technology, a stripped down Web Application into a webform functionality) from ASP.NET MVC to ASP.NET Core MVC. My current biggest problem is a static class that we had in the previous version of the webform. This static class uses packages that were available in .NET but not in .NET Core.

I understand that for some of the methods in this static class, I have to use dependency injection to resolve the package problems. However, it is not possible to pass a parameter to a static class making this an "antipattern" for .NET Core.

My Utils.cs static class has only two methods, RenderPartialToString and SendEmail. SendEmail is very simple and has no problems with the current .NET Core packages. However, I have the following code in my static class that does not work with current version.

public static class Utils
    {

        public static readonly string ApiUrl = ConfigurationManager.AppSettings["ApiUrl"];
        public static readonly string ApiKey = ConfigurationManager.AppSettings["ApiKey"];

        public static string RenderPartialToString(Controller controller, string viewName, object model)
        {
            controller.ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
                ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
                viewResult.View.Render(viewContext, sw);

                return "document.write('" + sw.GetStringBuilder().Replace('\n', ' ').Replace('\r', ' ').Replace("'","\\'").ToString() + "');";
            }
        }
    ...
    }

ViewEngine and ConfigurationManager are not available in .NET Core making this static class very difficult to migrate. I believe, I could implement both of these features with dependency injection. However, I do not know how to change this static class so that I can use dependency injection and be able to use these methods in my Controllers.

How can I simply migrate this static class into .NET Core for some dependency injection implementation? Do I need to change all the instances of the Utils class and make it not static?

Kemal Tezer Dilsiz
  • 3,739
  • 5
  • 24
  • 43
  • 1
    Eh what? "a webform app from ASP.NET MVC to... "? ASP.NET MVC is a different technology than ASP.NET (aka WebForms) – Tseng Aug 08 '16 at 15:53
  • 2
    See http://stackoverflow.com/questions/31905624/where-are-the-controllercontext-and-viewengines-properties-in-mvc-6-controller for the ViewEngine part. For ConfigurationManager, you need `IOption` https://docs.asp.net/en/latest/fundamentals/configuration.html – Kalten Aug 08 '16 at 15:55
  • @Tseng Sorry for not clarifying, it is a stripped down Web Application using MVC (not WebForms). Therefore, it is not a WebForm technology. – Kemal Tezer Dilsiz Aug 08 '16 at 15:59
  • @Kalten Good link with a great answer! :P – DavidG Aug 08 '16 at 16:02
  • @Kalten Thanks for the ViewEngine suggestion but I have already tried that, http://stackoverflow.com/questions/38749745/required-dependencies-for-resolver-or-serviceprovider-for-using-icompositeviewen and I will be looking into IOption now. – Kemal Tezer Dilsiz Aug 08 '16 at 16:02
  • @KemalTezerDilsiz In what way does the link from Kalten not work for you? The method name is almost identical. – DavidG Aug 08 '16 at 16:04
  • @DavidG I have provided the question that I have asked previously, explaining the situation with how that link does not work for me – Kemal Tezer Dilsiz Aug 08 '16 at 16:05
  • Also, just wanted to mention that for ConfigurationManager, I had this in mind http://www.danylkoweb.com/Blog/no-configurationmanager-in-aspnet-core-GC for implementation, a very recent article, maybe it may help someone who is also looking for a dependency injection solution for ConfigurationManager – Kemal Tezer Dilsiz Aug 08 '16 at 16:13

2 Answers2

9

You should refactor it into an object with non static methods, then register the object with DI services so it can be injected into your controller's constructor or wherever you need it.

I actually have a ViewRenderer class with similar functionality here that I use to generate html email using razor.

I register it with DI like this:

services.AddScoped<ViewRenderer, ViewRenderer>();

Note that my ViewRenderer also has it own constructor dependencies similar to what you need in your static method:

public ViewRenderer(
        ICompositeViewEngine viewEngine,
        ITempDataProvider tempDataProvider,
        IActionContextAccessor actionAccessor
        )
    {
        this.viewEngine = viewEngine;
        this.tempDataProvider = tempDataProvider;
        this.actionAccessor = actionAccessor;

    }

    private ICompositeViewEngine viewEngine;
    private ITempDataProvider tempDataProvider;
    private IActionContextAccessor actionAccessor;

ViewRenderer's constructor dependencies will also be passed into it by dependency injection, so the whole idea is to get away from all the static stuff and let everything be provided by DI.

If I need an instance of ViewRenderer in a Controller I can just add it to the constructor signature of the controller. Actually I don't use it directly in a controller since I use it for email, instead I have an EmailService which depends on ViewRenderer and the controller depends on EmailService

so you want to get to dependency injection all the way down for all dependencies, which is easy if you refactor away from static methods into object instance methods

Joe Audette
  • 35,330
  • 11
  • 106
  • 99
-1

Although i would go with @Joe's way, there may be another way for your case. To use controller extension method:

// register configuration
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IConfiguration>(Configuration);
}

public static class ControllerExtension
{
    public static string RenderPartialToString(this Controller controller, string viewName, object model)
    {
        controller.ViewData.Model = model;
        var config = controller.HttpContext.RequestServices.GetService<IConfiguration>();
        // other stuff
    }
}
adem caglin
  • 22,700
  • 10
  • 58
  • 78
  • You generally shouldn't have a notion of "configuration" during main execution. The concept with ASP.NET Core is you'd configure during init, creating an IApiService or whatever, and use that through DI. – Cory Nelson Aug 08 '16 at 16:43