I am migrating an ASP.NET Web API application to OWIN. That is not intended to use none OWIN deployments. So Global.asax is going to be removed. There are some code put into Global.asax event handlers specially in Application_EndRequest that should be handled by OWIN.
I have read some article about OWIN and searched the internet but couldn't determine how it can be done. Can anyone please describe how it can be done?
My environment:
Visual Studio 2015 RC
.Net Framework 4.5
Microsoft.AspNet.Cors.5.0.0
Microsoft.AspNet.WebApi.5.2.3
Microsoft.Owin.3.0.1
Owin.1.0
UPDATE: Here it is some sections of current code
using System;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using ProjectX.Web.AppStart;
using ProjectY.Domain.Contracts;
namespace ProjectX.UI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_EndRequest(object sender, EventArgs e)
{
var unitOfWork = DependencyResolver.Current.GetService(typeof(IUnitOfWork)) as IUnitOfWork;
unitOfWork.SaveChanges();
}
}
}
namespace ProjectY.Domain.Contracts
{
public interface IUnitOfWork
{
void SaveChanges();
IRepository<T> GetRepository<T>() where T : class, IEntity, IHistory;
IDbContext GetDbContext();
}
}
using ProjectY.Core.Repositories;
using ProjectY.Domain.Contracts;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProjectY.Core.UnitOfWork
{
public class UnitOfWork : IUnitOfWork
{
public UnitOfWork(IProjectYDbContextFactory contextFactory)
{
_context = contextFactory.GetContext();
}
public void SaveChanges()
{
if (_context == null)
throw new ApplicationException("Something wrong has been happened. _context must not be null.");
_context.SaveChanges();
}
}
}
I stumbled upon this question while updating some legacy applications. For those still seeking the answer: you can solve this by creating a middleware:
app.Use(async (context, next) =>
{
await next.Invoke().ConfigureAwait(false);
//Do stuff after request here!
var unitOfWork = DependencyResolver.Current.GetService(typeof(IUnitOfWork)) as IUnitOfWork;
unitOfWork.SaveChanges();
});
You can use stage markers if you need more control on when your middleware will be called in the request processing pipeline.
See also https://learn.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-middleware-in-the-iis-integrated-pipeline#stage-markers
Related
I'm trying to build my first NserviceBus application, but I cannot get it to work. The message arrives on the "backend" but the handler uses DI and NServicebus claims it cannot find the service for the interface. But the code was lifted directly from the examples. I'm missing something and I cannot figure it out.
The Error:
dbug: NServiceBus.LoadHandlersConnector[0]
Processing message type: Messages.JobStartCommand
Message headers:
NServiceBus.MessageId : 0044f261-e3b3-4287-b6f0-ad7400ef43cb
NServiceBus.MessageIntent : Send
NServiceBus.ConversationId : bb4f276f-63fe-450b-b234-ad7400ef43cd
NServiceBus.CorrelationId : 0044f261-e3b3-4287-b6f0-ad7400ef43cb
NServiceBus.ReplyToAddress : ClientUI
NServiceBus.OriginatingMachine : L19002992
NServiceBus.OriginatingEndpoint : ClientUI
$.diagnostics.originating.hostid : e1fecb2b72b8185e47341bb4dfb37dd7
NServiceBus.ContentType : text/xml
NServiceBus.EnclosedMessageTypes : Messages.JobStartCommand, Messages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
NServiceBus.Version : 7.5.0
NServiceBus.TimeSent : 2021-07-29 14:31:08:228497 Z
NServiceBus.Retries : 3
NServiceBus.Retries.Timestamp : 2021-07-29 14:31:40:397277 Z
Handlers to invoke:
Extractor.JobStartHandler
Extractor.JobStartHandler
info: NServiceBus.RecoverabilityExecutor[0]
Immediate Retry is going to retry message '0044f261-e3b3-4287-b6f0-ad7400ef43cb' because of an exception:
System.InvalidOperationException: Unable to resolve service for type 'IExtract' while attempting to activate 'Extractor.JobStartHandler'.
at Microsoft.Extensi
My backend program.cs
using Microsoft.Extensions.Hosting;
using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NServiceBus;
using System.Threading.Tasks;
using Messages;
using Extractor;
namespace ExtractorOsiris
{
class Program
{
static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var builder = Host.CreateDefaultBuilder(args);
builder.UseWindowsService();
//builder.UseMicrosoftLogFactoryLogging();
builder.ConfigureLogging((ctx, logging) =>
{
logging.AddConfiguration(ctx.Configuration.GetSection("Logging"));
//logging.AddEventLog();
logging.AddConsole();
logging.SetMinimumLevel(LogLevel.Debug);
});
#region back-end-use-nservicebus
builder.UseNServiceBus(ctx =>
{
var endpointConfiguration = new EndpointConfiguration("Sample.Extractor");
endpointConfiguration.UseTransport<LearningTransport>();
var transport = endpointConfiguration.UseTransport<LearningTransport>();
transport.Routing().RouteToEndpoint(typeof(ProcessObjectCommand), "Sample.Processor");
endpointConfiguration.DefineCriticalErrorAction(OnCriticalError);
return endpointConfiguration;
});
#endregion
#region back-end-register-service
builder.ConfigureServices(services =>
{
services.AddSingleton<IExtract, ExtractOsiris>();
});
#endregion
return builder;
}
private static Task OnCriticalError(ICriticalErrorContext arg)
{
throw new NotImplementedException();
}
}
}
The Interface
using Newtonsoft.Json.Linq;
using NServiceBus;
using System;
using System.Threading.Tasks;
namespace Extractor
{
public interface IExtract
{
Task<JArray> Extract(string #object, DateTime deltaTime);
}
}
The handler
using System.Threading.Tasks;
using Messages;
using Newtonsoft.Json.Linq;
using NServiceBus;
namespace Extractor
{
#region back-end-handler
public class JobStartHandler : IHandleMessages<JobStartCommand>
{
private readonly IExtract extractor;
public JobStartHandler(IExtract extractor)
{
this.extractor = extractor;
}
public async Task Handle(JobStartCommand message, IMessageHandlerContext context)
{
Task<JArray> result = extractor.Extract("Medewerkers", message.DeltaTime);
await result;
JArray test = result.Result;
foreach (JObject x in test)
{
// send the object to be processed.
//await context.Send(new ProcessObjectCommand(x.ToString()));
}
}
}
#endregion
}
The implementation of the interface
using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Extractor;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NServiceBus;
namespace ExtractorOsiris
{
public class ExtractOsiris : IExtract
{
private readonly ILogger logger;
public ExtractOsiris(ILogger<ExtractOsiris> logger)
{
this.logger = logger;
}
public Task<JArray> Extract(string #object, DateTime deltaTime)
{
logger.LogInformation($"getting {#object} for delta time {deltaTime}");
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://xx.yy");
WebResponse response = request.GetResponse();
JObject temp = JObject.Load(new JsonTextReader(new StreamReader(response.GetResponseStream())));
return Task<JArray>.FromResult(temp["items"] as JArray);
}
}
}
I know the code ain't pretty, but it's pure quick and dirty testing code.
I cleaned out the offending interface from the code and still got the error on an interface that was not even there anymore. I removed the bin folder and build everything back up step by step. Stupid thing is, source control says I am back where I started, without changes. And it just works....
So must have bin something stupid with VS2019. Sorry to anyone who's time I wasted
Below is the sample I found from online Tutorial to host the website suing OWIN, however when I try to run on my machine, I got this error
CS0246 The type or namespace name 'Func<,>' could not be found (are you missing a using directive or an assembly reference?)
I think for using 'Func<,>' I have using System, and for IDictionary, I have using System.Collections.Generic; so I don't understand why it still can't work.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
using AppFunc = Func<IDictionary<string, object>, Task>;
public class Startup
{
public void Configuration(IAppBuilder app)
{
var middleware = new Func<AppFunc, AppFunc>(MyMiddleWare);
app.Use(middleware);
app.Use<OtherMiddleware>();
}
public AppFunc MyMiddleWare(AppFunc next)
{
AppFunc appFunc = async (IDictionary<string, object> environment) =>
{
var response = environment["owin.ResponseBody"] as Stream;
byte[] str = Encoding.UTF8.GetBytes("My First Middleware");
await response.WriteAsync(str, 0, str.Length);
await next.Invoke(environment);
};
return appFunc;
}
public class OtherMiddleware : OwinMiddleware
{
public OtherMiddleware(OwinMiddleware next) : base(next) { }
public override async Task Invoke(IOwinContext context)
{
byte[] str = Encoding.UTF8.GetBytes(" Other middleware");
context.Response.Body.Write(str, 0, str.Length);
await this.Next.Invoke(context);
}
}
}
You need to put the AppFunc in the class so it can use the using,
Or you can use full namespace for Func, IDictionary and Task
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
// Use this
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
public class Startup
{
// Or this
using AppFunc = Func<IDictionary<string, object>, Task>;
...
}
For me it was low .NET Target Framework version 2.0 of application. Changed to 4.7 (it seems minimal is 3.5).
You need to make sure you added the reference System.Runtime.CompileServices to your project as you see in here: https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx the delegate is part of mscorlib assembly.
I want to access full capabilities of SimpleMembershipProvider such as ValidateUser method.
So according to its documentation I should not call WebSecurity.InitializeDatabaseConnection() for initialization and instead enable standard membership and role providers.
My question is: How can I initialize SimpleMembershipProvider class
To Finally: have access to full capabilities of SimpleMembershipProvider
or if there is a better solution, thanks
How can I initialize SimpleMembershipProvider class
If you look at the default ASP.NET MVC 4 Internet application template the AccountController is decorated with the [InitializeSimpleMembership] attribute. That's how it is initialized in this sample. This means that you will be able to use it once you have gone through the account controller, not before. If you want to use your membership provider before authenticating you could do the same in your Application_Start method.
If you were to merge the InitializeSimpleMembershipAttribute into the Global.asax.cs Application_Start so that the SimpleMembershipProvider would be initialized without any AccountController routes being called...
...it could look something like this: http://aaron-hoffman.blogspot.com/2013/02/aspnet-mvc-4-membership-users-passwords.html
// The using below is needed for "UsersContext" - it will be relative to your project namespace
using MvcApplication1.Models;
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Threading;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using WebMatrix.WebData;
namespace MvcApplication1
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
// Ensure ASP.NET Simple Membership is initialized only once per app start
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
}
}
}
I have an ASP.net project which involves using a custom IHttpModule. This module will sit in the pipeline and when certain criteria match up, it should invoke a method on a WCF service hosted in a simple C# console application on the same machine.
The code for the module is below:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.SessionState;
using System.Web;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Configuration;
using System.ServiceModel;
using SimpleFarmStateServer;
namespace SimpleFarm
{
public class SimpleFarmModuleSS : IHttpModule, IRequiresSessionState
{
protected string cache_directory = "";
// WCF
ChannelFactory<IStateServer> factory;
IStateServer channel;
public void Dispose() { }
public void Init(System.Web.HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
setupFactory();
}
void setupFactory()
{
factory = new ChannelFactory<IStateServer>(
new NetNamedPipeBinding(),
"net.pipe://localhost/StateServer");
}
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
try
{
if (factory.State != CommunicationState.Opened)
setupFactory();
channel = factory.CreateChannel();
channel.LogAccess("Hello World!");
}
catch (Exception ex)
{
}
finally
{
factory.Close();
}
}
}
}
My problem is that this runs the first time, but then subsequent attempts cause this error message
The communication object,
System.ServiceModel.Channels.ServiceChannel,
cannot be used for communication
because it is in the Faulted state.
It seems as if I am doing something wrong, and I am new to WCF in general so this is very likely.
I think the issue is surrounding the ChannelFactory being recreated, and this causes the faulted state.
The specific error probably means the factory faulted, threw an exception (which you're swallowing) and then when the finally block executes, the factory.Close() call fails because the factory is faulted (if a WCF object is faulted, you need to call Abort() on it, not Close()).
Does anyone know any resources regarding to the creation of a custom scheduled task under Telligent 5.5 ?
From what I read, all I need to do is the following:
1.Create a type that implements the ITask2 interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Telligent.Tasks;
namespace Project.ScheduledTasks
{
public class ReminderTask:ITask2
{
public void Execute()
{
string task = "Please hit the breakpoint here";
}
public void Load(System.Xml.XmlNode node)
{
throw new NotImplementedException();
}
}
}
2.Add the task description in the communityserver.config
<Thread minutes="1">
<task name="ReminderTask" type="Project.ScheduledTasks.ReminderTask, Project.ScheduledTasks" enabled="true" enableShutDown="false"></task>
</Thread>
Do I need to do anything else ?
Please help :).
Yes, that is all that you should need to do. Are you having issues?