Utilizing a WCF channel from an IIS ASP.net IHttpModule - asp.net

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()).

Related

NServicebus not unable to resolve service for interface in handler

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

create a service to return my external ip

Hi is there any way to create my own page in my web server so that i can ping it from external application to get the WAN ip from where the application is hosted? Something like whatismyip but on my own server.
What about next code:
using System;
using System.Web;
namespace WebApplication1
{
public class Global : HttpApplication
{
protected void Application_BeginRequest(object sender,
EventArgs e)
{
// Get request.
HttpRequest request = base.Request;
// Get UserHostAddress property.
string address = request.UserHostAddress;
// Write to response.
base.Response.Write(address);
// Done.
base.CompleteRequest();
}
}
}

What is OWIN equivalent for Application_EndRequest?

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

Asp.Net OData V4: How can I get exceptions to bubble up to a global handler?

I am relatively new to Asp.Net OData. What I have realized is that the ODataMediaTypeFormatter logs exceptions like JSON deserialization issues and does not throw an exception. So I created a ModelValidationFilterAttribute and enabled it globally through HttpConfiguration.
public class ModelValidationFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response =
actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest,
actionContext.ModelState);
}
}
}
The problem with this is that things like System.InsufficientExecutionStackException also get sent down to the client using this validation filter.
I want model validation state to be sent to the client when there is an error in the model format/data. For code exceptions, I would prefer that the exception just bubble up to a global handler where I can log, check the exception type, and respond to the client accordingly.
You may want to create an exception filter like this:
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http.Filters;
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
then you can control how to respond to the client. In the above example, it send 501 to the client.
References:
http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling
http://www.asp.net/web-api/overview/web-api-routing-and-actions/web-api-global-error-handling

How to Initialize SimpleMembershipProvider?

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);
}
}
}
}
}

Resources