Unable to run my asp.net mvc web application after installing HangFire - asp.net

I am working on an asp.net MVC-5 web application, and using nuget i installed the hangfire tool:-
Install-Package Hangfire
but when i run my application i got this exception:-
The following errors occurred while attempting to load the app.
- No assembly found containing an OwinStartupAttribute.
- No assembly found containing a Startup or [AssemblyName].Startup class.
To disable OWIN startup discovery, add the appSetting owin:AutomaticAppStartup with a value of "false" in your web.config.
To specify the OWIN startup Assembly, Class, or Method, add the appSetting owin:AppStartup with the fully qualified startup class or configuration method name in your web.config.
second question. if i got the above error fix, how i can call an action method on predefined intervals using hangfire. currently i am defining this inside my glabal.asax as follow:-
static void ScheduleTaskTrigger()
{
HttpRuntime.Cache.Add("ScheduledTaskTrigger",
string.Empty,
null,
Cache.NoAbsoluteExpiration,
TimeSpan.FromMinutes(60)),
CacheItemPriority.NotRemovable,
new CacheItemRemovedCallback(PerformScheduledTasks));
}
static void PerformScheduledTasks(string key, Object value, CacheItemRemovedReason reason)
{
//Your TODO
HomeController h = new HomeController();
var c = h.ScanServer("12345", "allscan");
ScheduleTaskTrigger();
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
ScheduleTaskTrigger();
}
----EDIT----------
now after adding the startup.css class , i defined the following inside my global.asax :-
HomeController h = new HomeController();
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
// ScheduleTaskTrigger();
RecurringJob.AddOrUpdate(() => h.ScanServer("12345","allscan"), Cron.Minutely);
}
mainly to call an action method named "ScanServer" under the Home controller. now the ScanServer is an async task which have the following defenition :-
public async Task<ActionResult> ScanServer(string tokenfromTMS, string FQDN)
{
so my global.asax is raising this error :-
Async methods are not supported. Please make them synchronous before using them in background.

It seems that your OWIN startUp class is missing, So create a class with name Startup:
public class Startup
{
public void Configuration(IAppBuilder app)
{
//..codes
}
}
For your second question, if you want to call a method, for example each hour you can use RecurringJob:
RecurringJob.AddOrUpdate(() => CallMethod(), Cron.Hourly);

Related

How to pass IOptions to an ASP.NET 5 middle-ware service?

I have started playing around with ASP.NET 5 vNext and I am struggling passing the options from config.json into a middle-ware service that is used by my WebApi controller.
Here is a snippet with my middle-ware service:
public class MyService : IMyService
{
public MyService(IOptions<MyOptions> settings)
{
var o = settings.Options;
}
}
Here is my WebApi controller that is using the middle-ware service:
public class MyController : Controller
{
private IMyService _myService;
public TestController(IMyService service)
{
_myService = service;
}
}
In Startup.cs I am reading the options:
services.AddOptions();
services.Configure<MyOptions>(Configuration);
What I am struggling with is how to register an instance to IMyService so that it would be passed to the constructor of the controller (how can I get a hold of the IOptions)?
services.AddInstance<IMyService>(new MyService(XXXXX));
As suggested below I did try to use both
services.AddTransient<MyService>();
and
services.AddSingleton<MyService>();
But in both cases I am seeing the following error:
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type
'MyApp.Services.IMyService' while attempting to activate
'MyApp.Controllers.TestController'.
Microsoft.Framework.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider
sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
Thanks for your help!
Don't register it as an Instance. Instead just add it as Scoped/Transient/Singleton depending on your requirements and let Dependency Injection do its magic;
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddScoped<IMyService, MyService>();
For example, you can to add to Startup.cs that code:
public void ConfigureServices(IServiceCollection services)
{
var builder = new ConfigurationBuilder("[path to file with configuration]");
builder.AddJsonFile("config.json");
var config = builder.Build();
services.AddOptions();
services.Configure<MyOptions>(config);
//services.AddSingleton<IMyService, MyService>();
services.AddTransient<IMyService, MyService>();
}
I can assure you that you can use Singleton or Transient.
If you're interested, you can find more info here https://github.com/aspnet/Docs/issues/24.
And additionally, currently Autofac creates DI for ASP.NET 5 on
http://alexmg.com/autofac-4-0-alpha-1-for-asp-net-5-0-beta-3/

ASP.NET 5 (vNext) - Using Filters

I have an ASP.NET MVC app that I am trying to migrate to MVC 6 (ASP.NET 5). With that in mind, I have some filters that were added using the process described in this SO post. However, with Global.asax being replaced with Startup.cs, I'm not sure where to add my global filters anymore.
In addition, in my filter I have:
public override void OnResultExecuting(ResultExecutingContext context)
{
context.Controller.ViewBag.MyProperty = "[TESTING]";
}
When I run dnx . run now, I get an error that says:
MyFilter.cs(11,22): error CS1061: 'object' does not contain a definition for 'ViewBag' and no extension method 'ViewBag' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
How do I add global filters in ASP.NET 5 (MVC 6)?
To register global filter you can do following:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().Configure<MvcOptions>(options =>
{
options.Filters.Add(new YourCustomFilter());
});
}
in your Startup.cs
Regarding error you're getting, context.Controller has object type and therefore ViewBag property can't be resolved. Cast it to Controller type first:
public override void OnResultExecuting(ResultExecutingContext context)
{
var controller = (Controller) context.Controller;
controller.ViewBag.MyProperty = "[TESTING]";
}

Global exception handling in ASP.NET 5

How can I attach my own logging logic to an ASP.NET 5 application to handle each exception thrown in the business logic and lower layers?
I tried with own ILoggerProvider implementation and loggerfactory.AddProvider(new LoggerProvider(Configuration)) in Startup.cs. But it seems that it intercepts inner ASP.NET stuff, and not my thrown exceptions in lower layers.
Worked it out, by using two options:
1) ILoggerProvider
Implement your own ILoggerProvider and ILogger from the namespace Microsoft.Framework.Logging Then attach it to the MVC Framework in Startup.cs add following code:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
loggerfactory.AddProvider(new YourCustomProvider());
}
But this above option, seems to only call the Write function of the ILogger on MVC specific events, routing related and so on, it wasn't called when I threw exceptions on my lower layers, so the second option worked out:
2) Global Filter
Register your own ActionFilterAttribute implementation in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().Configure<MvcOptions>(options =>
{
options.Filters.Add(new YourCustomFilter());
});
}
It's important, that the custom filter class implements the IExceptionFilter interace:
public class YourCustomFilter : ActionFilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext context)
{
///logic...
}
}
(EDIT:)
And then in the Startup class we add the filter:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(new YourCustomFilter());
});
}
If you want a really global exception trap framework, not just at the controller level, take a look at one of my open source projects. I plan to make it into a Nuget Package soon after the holidays. I'm also planning to update my blog showing why I developed it.
The open source project is on github:
https://github.com/aspnet-plus/AspNet.Plus.Infrastructure
Take a look at the sample for usage.

Structure Map Error Code 202

I am fairly used to using Structure Map IoC with MVC, but have recently had to adapt it to legacy web forms.
I have done this by providing a IoCContainer class that has a Configure() method on it such as the following that handles the registry.
public static void Configure()
{
var log = LogManager.GetLogger(typeof (Global1));
log.Debug("Initializing Container");
/*Initialize IoC Container*/
ObjectFactory.Initialize(x =>
{
x.For<ITokenService>().Use<TokenService>();
x.For<ILocalizationService>().Use<LocalizationService>();
log.Debug("Initializing Object Factory");
/*Setup Property Injection*/
x.SetAllProperties(p =>
{
p.OfType<ITokenService>();
p.OfType<ILocalizationService>();
});
});
}
I have provided a base control that contains the BuildUp() method BasePage.cs, such as the following.
public BasePage()
{
var log = LogManager.GetLogger(typeof (Global1));
log.Debug("Base Page Build Up");
/*Inject Dependencies*/
ObjectFactory.BuildUp(this);
}
In one of my classes I am using autowiring to inject the LocalizationService into an ILocalization Property.
Everything works perfectly fine on my local machine, but for some reason, when I deploy this code to our staging server, it is giving me the following StructureMap Exception:
StructureMap Exception Code: 202
No Default Instance defined for PluginFamily SuperShuttle.Web.Applications.Reservations.Interfaces.Services.ILocalizationService, SuperShuttle.Web.Applications.Reservations, Version=3.6.27.0, Culture=neutral, PublicKeyToken=null
Not quite sure why it would change when I deploy my application, especially since I am just copying and pasting the files.
Edit I am calling IoCContainer.Configure() in Application_Start() of Global.asax such as the following:
protected void Application_Start(object sender, EventArgs e)
{
log.Debug("In Application Start - Pre BuildUp");
/*Configure Ioc Container*/
IocConfigurator.Configure();
}

Using Autofac for DI into WCF service hosted in ASP.NET application

I'm having trouble injecting services dependencies into my WCF service using Autofac 1.4.5. I've read and followed the Autofac wiki page on WcfIntegration but my debugging shows me that my WCF service is created by the System.ServiceModel.Dispatcher.InstanceBehavior.GetInstance() method and not by the AutofacWebServiceHostFactory. What am I doing wrong?
I've set up my ajax.svc file to look like the one in the example for use with WebHttpBinding:
<%# ServiceHost Language="C#" Debug="true"
Service="Generic.Frontend.Web.Ajax, Generic.Frontend.Web"
Factory="Autofac.Integration.Wcf.AutofacWebServiceHostFactory,
Autofac.Integration.Wcf" %>
My WCF service class Ajax is defined like this:
namespace Generic.Frontend.Web
{
[ServiceContract]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Ajax
{
public MapWebService MapWebService { get; set;}
public Ajax() {
// this constructor is being called
}
public Ajax(MapWebService mapWebService)
{
// this constructor should be called
MapWebService = mapWebService;
}
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract(Name = "mapchange")]
public MapChangeResult ProcessMapChange(string args)
{
// use the injected service here
var result = MapWebService.ProcessMapChange(args);
return result;
}
}
}
Now I've used the wiring up in the Global.asax.cs as shown in the wiki mentioned above:
var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacModuleWebservice());
var container = builder.Build();
AutofacServiceHostFactory.Container = container;
with
class AutofacModuleWebservice : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register<Ajax>();
builder.Register<MapWebService>().ContainerScoped();
}
}
In my web.config I have
<services>
<service name="Generic.Frontend.Web.Ajax">
<endpoint address="http://mysite.com/ajax.svc/" binding="webHttpBinding"
contract="Generic.Frontend.Web.Ajax" />
</service>
</services>
.
The service already works fine but I can't get the Autofac bits (read: creation/injection) to work. Any ideas?
Edit:
Removing the default constructor unfortunately leads to the following exception:
System.InvalidOperationException:
The service type provided could not be loaded as a service because it does not
have a default (parameter-less) constructor. To fix the problem, add a default
constructor to the type, or pass an instance of the type to the host.
Cheers, Oliver
Is your service setup with InstanceContextMode.Single? If it is then wcf will create your service using the default constructor. To get around this change your instance context mode and let autofac manage the lifetime of your service.
Try deleting the default Ajax constructor and modifying your constructor to this. If it gets run with mapWebService == null that would indicate a resolution problem.
public Ajax(MapWebService mapWebService = null)
{
// this constructor should be called
MapWebService = mapWebService;
}
I just got the same System.InvalidOperationException and solved it by changing the ServiceBehavior InstanceContextMode of the implementation from InstanceContextMode.PerCall to InstanceContextMode.PerSession, perhaps your AutoFac lifetime scope is out of sync with your web service implementation?
For testing AutoFac service creation I recommend creating a unit test and directly resolving them as this will highlight any issues and give more meaningful exception messages. For services with a request lifetime scope create a test aspx page and again resolve them directly.
I had the same problem and came across this question while searching for an answer.
In my case, using property injection worked, and the code in the question already has a property that can be used:
namespace Generic.Frontend.Web
{
[ServiceContract]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Ajax
{
// inject the dependency here
public MapWebService MapWebService { get; set;}
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract(Name = "mapchange")]
public MapChangeResult ProcessMapChange(string args)
{
// use the injected service here
var result = MapWebService.ProcessMapChange(args);
return result;
}
}
}
and register to use property injection (sample code from the wiki and syntax has changed as this is now using version 2.5.2.830):
builder.RegisterType<Ajax>().PropertiesAutowired();
Following the instructions solved it for me:
code.google.com/p/autofac/wiki/… I simply do : builder.RegisterType();
and I've followed their instuructions for changing the .svc file.
When you look at your .svc file you do not get any hints about something being wrong there btw?
You host it throu the iis and do not utilize WAS, I do not see your code for overriding global.asax.cs
Add the global file to your solution and there you implement:
protected void Application_Start(object sender, EventArgs e)
{
// build and set container in application start
IContainer container = AutofacContainerBuilder.BuildContainer();
AutofacHostFactory.Container = container;
}
AutofacContainerBuilder is my container builder.

Resources