I have an asp.net core application hosted and webdav enabled in IIS for storing files as well. I want to know when a user saves a file in the webdav server (ie, if opened and saved in Microsoft word). I have put together this IIS module to try and intercept all http requests so I can find out what a webdav HTTP requests look like and then hopefully create a if statement using this logic once I can identify the save request. So far here is the IIS module I have created:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace WebDAVTargetDetectorIIS
{
public class LoggingModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(OnPreRequestHandlerExecute);
context.PostLogRequest += new EventHandler(PostLogEvent);
}
#endregion
public void OnPreRequestHandlerExecute(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpRequest request = app.Context.Request;
if (!String.IsNullOrEmpty(request["HTTP_CF_CONNECTING_IP"]))
{
request.ServerVariables.Set("REMOTE_ADDR", request["HTTP_CF_CONNECTING_IP"]);
}
}
public void PostLogEvent(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpRequest request = app.Context.Request;
app.Response.AppendToLog("This is a test");
}
}
}
I have created the BIN folder in the root folder of my web application and used the IIS Manager to add the new module. It is added to the end of the ordered list. The log files in IIS seem to save to "C:\inetpub\logs\LogFiles\W3SVC1" however my module does not seem to be printing my test line in there. Is there a particular reason the code above would not implement on any even a login request? Or should I be attaching this to some other event?
Related
I am trying to use the BackgroundService is an asp.net core 2.2 project using the Razor page project template, not MVC. This little sample app took me about 1 minute to write so it couldn't be much simpler. Looking at the debugger I know the background service is starting and chugging along just fine. But when I attempt to navigate to a page (path 'Banana') that requires this service as a dependency, I get InvalidOperationException: Unable to resolve service for type 'WebApplication23.DumbService' while attempting to activate 'WebApplication23.Pages.BananaModel'. Why can't I access this service from my page model? The code is at https://github.com/jmagaram/SimpleBackgroundService
I have the following service:
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
namespace WebApplication23
{
public class DumbService : BackgroundService
{
public DumbService()
{
}
public void QueueWork()
{
}
protected async override Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested) {
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
}
}
And this is where I register it:
services.AddHostedService<DumbService>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Here is a page model that uses it:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace WebApplication23.Pages
{
public class BananaModel : PageModel
{
private readonly DumbService _service;
public BananaModel(DumbService service)
{
_service = service;
}
public void OnGet()
{
}
}
}
Registering a background service doesn't actually add it to the service collection, mostly because there's no need to. The whole point of a background service is that your app doesn't really need to know about it. It's not clear why you think you need this service injected, but almost certainly you'd be better served by factoring out whatever logic you need in your Razor Page into a separate class that both the service and your Razor page can utilize.
UPDATE
See the documentation on IHostedService where an example of a queue background service is given. You'll notice that the actual hosted service is injected with the task queue. Your app then would also inject just the task queue itself to schedule tasks.
I am trying to implement a simple Breeze controller in Asp.Net MVC4, but can't seem to access it. Is it possibly conflicting with .Net's standard Web.Api ?
If my url is http://localhost:49479/api/values then I get a good return value from Web Api.
However if my url is http://localhost:49479/breeze/Breeze I get "Http 404" error "Resource not found".
If my url is http://localhost:49479/breeze/Breeze/5 I get error No HTTP resource was found that matches the request URI 'http://localhost:49479/breeze/Breeze/5'.
Your advice is greatly appreciate.
Here's what I have in ..Controllers/BreezeController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Breeze.ContextProvider;
using Breeze.WebApi2;
using Newtonsoft.Json;
namespace RageSys.Controllers
{
[BreezeController]
public class BreeezeController : ApiController
{
// GET api/values
public string Get(int id)
{
return "value";
}
public IEnumerable<string> GetMtm(int id)
{
return new string[] { "value1", "value2" };
}
}
}
and in BreezeWebApiConfig.cs :
using System.Web.Http;
[assembly: WebActivator.PreApplicationStartMethod(
typeof(RageSys.App_Start.BreezeWebApiConfig), "RegisterBreezePreStart")]
namespace RageSys.App_Start {
///<summary>
/// Inserts the Breeze Web API controller route at the front of all Web API routes
///</summary>
public static class BreezeWebApiConfig {
public static void RegisterBreezePreStart() {
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "breeze/{controller}/{action}"
);
}
}
}
The result you are getting from your api/values request is not coming from the listed controller. You must have the default ValuesController and WebApiConfig (which defines a route that takes a parameter) still in your project.
You do not have a route for http://localhost:49479/breeze/Breeze/5. The third segment (currently 5) needs to be the name of an Action method. For you, that means GetMtm. You do not have a route that takes any parameters, so you'll get nothing from: http://localhost:49479/breeze/Breeze/GetMtm/5 unless you define such a route. You probably don't want to do this though, because Breeze coupled with Entity Framework will make life very easy. You should implement the simplest possible Breeze / Entity Framework application and see how it works from there.
If you are using parameters and using Breeze, then ensure you use the .withParameters({ ParameterName: "Fred"}) or .withParameters({ id: id-value}), for example, in your Breeze query and ensure the parameter name in your function to be called (GetMtm in your case) at the server matches the parameter name you are using at the client.
I'm in the process of converting an ASP.NET MVC3 (LinqToSQL, EntityFramework) project to MVC4. I've created a fresh MVC4 project in VS2012, added packages, copied my Views, Controllers, etc.
Most things seem to work fine except when I try to access a controller that makes use of a Respository, as follows:
public class CustomerController : Controller
{
private ICustomerRepository _cr;
public CustomerController()
{
this._cr = new CustomerRepository(TTDataProvider.DB);
}
public CustomerController(ICustomerRepository customerRepository)
{
this._cr = customerRepository;
}
if I'm in VS2012 and debugging, what I'll get is an exception: "Activation error occured while trying to get instance of type CustomerController, key """. The exception is of type Microsoft.Practices.ServiceLocation.Activation and the Inner Exception is: "StructureMap Exception Code: 202\nNo Default Instance defined for PluginFamily TTLW.Models.TTLWDataContext, TTLW, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}.
My IoC code is:
using StructureMap;
using FluentSecurity;
using System.Diagnostics;
namespace TTLW {
public static class IoC {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.AddAllTypesOf<IPolicyViolationHandler>();
});
});
return ObjectFactory.Container;
}
}
}
And here's StructureMapMVC.cs
using System.Web.Http;
using System.Web.Mvc;
using StructureMap;
using TTLW.DependencyResolution;
[assembly: WebActivator.PreApplicationStartMethod(typeof(TTLW.App_Start.StructuremapMvc), "Start")]
namespace TTLW.App_Start {
public static class StructuremapMvc {
public static void Start() {
IContainer container = IoC.Initialize();
DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = DependencyResolver.Current.ToServiceResolver();
}
}
}
As I say, this was all working without problems in my MVC3 application (although I was of course using the MVC3 version of StructureMap).
Once I hit the exception, if I just choose to continue then everything works (i.e. the controller functions); this is confirmed by choosing "Start Without Debugging" instead of "Debug". When I do that there is no exception thrown and things work as designed.
I've searched and come across posts from Phil Haack, Brett Allred and others (in fact I've already incorporated Allred's code in the last line of StructureMapMVC) but haven't found a solution. I can't consider the project converted as long as this exception is staring me in the face.
I've included all the code and messages I think are reasonable and would appreciate any insights. If you need to see more just let me know.
Thanks in advance.
I have this strange problem where my client will hang when it calls a method from my WCF Service. Now the real strange thing is that this does not happen when the Client is a Console Application. It does happen when the client is a WinForm or WPF application.
I created a Client Library that a WCF Client can use to connect to the Service, seen here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel; //needed for WCF communication
namespace DCC_Client
{
public class DCCClient
{
private DuplexChannelFactory<ServiceReference1.IDCCService> dualFactory;
public ServiceReference1.IDCCService Proxy;
public DCCClient()
{
//Setup the duplex channel to the service...
NetNamedPipeBinding binding = new NetNamedPipeBinding();
dualFactory = new DuplexChannelFactory<ServiceReference1.IDCCService>(new Callbacks(), binding, new EndpointAddress("net.pipe://localhost/DCCService"));
}
public void Open()
{
Proxy = dualFactory.CreateChannel();
}
public void Close()
{
dualFactory.Close();
}
}
public class Callbacks : ServiceReference1.IDCCServiceCallback
{
void ServiceReference1.IDCCServiceCallback.OnCallback(string id, string message, Guid key)
{
Console.WriteLine(string.Format("{0}: {1}", id, message));
}
}
}
Here is the code for the working WCF Console Client:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DCC_Client;
namespace Client_Console_Test
{
class Program
{
private static DCCClient DCCClient;
static void Main(string[] args)
{
try
{
DCCClient = new DCCClient();
DCCClient.Open();
DCCClient.Proxy.DCCInitialize(); //returns fine from here
Console.ReadLine();
DCCClient.Proxy.DCCUninitialize();
DCCClient.Close();
}
catch (Exception e)
{
throw;
}
}
}
}
And here is the code for the WPF Client that freezes (see comment)
using System; //etc
using DCC_Client; //Used for connection to DCC Service
namespace Client_WPF_Test
{
public partial class Main : Window
{
private static DCCClient DCCClient;
public Main()
{
InitializeComponent();
DCCClient = new DCCClient();
DCCClient.Open();
}
private void Connect_btn_event() {
try
{
DCCClient.Proxy.DCCInitialize(); //**never returns from this**
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
I stepped into the code DCCClient.Proxy.DCCInitialize(); and the service executes the commands successfully, however, for some reason the client gets stuck here and does not continue executing. The client gives no exception, and the stack trace says [external code].
That being said, the Console Client runs perfectly. I think I am missing something simple here. I appreciate any help you can provide.
In case that your service call backs the client directly from DCCInitialize and both operation and callback operation are not marked as one-way your application will deadlock. Try marking your callback implementation with this attribute:
[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)]
Instead of this you can also try to mark operations in both contracts with
[OperationContract(IsOneWay=true)]
But both operations must return void
For the last if neither of these helps try to mark your callback implementation with:
[CallbackBehavior(UseSynchronizationContext=false)]
but in this case your callback operation will run in another thread and it will not be able to manipulate with UI controls directly.
Edit:
WCF behaves differently when hosted in UI thread. In such scenario all request are processed in sequential order in standard windows message loop so if you call the service you blocked your current thread but the service calls back your client and it waits to process the message but it can't because thread is blocked by the initial call = deadlock until initial request timenouts. By using last mentioned behavior you will say WCF to not join windows message loop and instead process messages in separate threads as usual. There is no security issue with this except the fact that you cannot access UI control from methods running in other threads - both WinForms and WPF has approaches to pass commands from other thread.
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using BankServiceClient.BankServiceReference;
namespace BankServiceClient
{
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8000/Simple");
Type instanceType = typeof(BankServiceReference.BankClient);
ServiceHost host = new ServiceHost(instanceType,baseAddress);
using (host)
{
Type contractType = typeof(BankServiceReference.IBank);
string relativeAddress = "BankService";
host.AddServiceEndpoint(contractType, new BasicHttpBinding(), relativeAddress);
host.Open();
Console.WriteLine("Press <ENTER> to quit.");
Console.ReadLine();
host.Close();
}
/*
* Consuming a WCF Service and using its method.
*/
//IBank proxy = new BankClient();
//double number = proxy.GetBalance(1234);
//Console.WriteLine(number.ToString());
//Console.ReadLine();
}
}
}
First, a couple of questions:
The 'baseAddress' attribute, what exactly is it? When I launched my service using the default F5 (no console application) the service launched on a random port on localHost. How can I write in an exact number and expect it to go there? Confused at this one.
What is the relativeAddress attribute? It says BankService but what should I write in that attribute? Confused at this one as well.
Here's the exact error message I get when I try to run this Console application:
HTTP could not register URL
http://+:8000/Simple/. Your process
does not have access rights to this
namespace (see
http://go.microsoft.com/fwlink/?LinkId=70353
for details).
First is your client project set to be the start up project?
And to answer your questions.
1) baseAddress (URI Class) is the base address for your hosted service. I am thinking you are launching some other project.
2) You have two options on configuring endpoints(reference). Relative and Absolute. The way you did it will take your base and appends your relative -> http://localhost:8000/Simple/BankService
Lastly to fix your hosting issue see this SO link:
WCF ServiceHost access rights