When a video request is handled by the HTTP Module (code below) such as /website/uploads/Video/M2U00001_2.mp4 the _context.User is null.
When I run this in VS2010 on my local machine using the Visual Studio Development server _context.User is set. After I deploy to IIS 7 (.net 4.0) _context.User is Null.
'_context.User' is not Null when the http module processes an aspx page but it is Null when processing javascript, images, videos or CSS.
Can anyone explain why _context.User is null and possible solutions that will ensure _context.User is not null.
public Class VideoSecurityModule
Implements IHttpModule
Private WithEvents _context As HttpApplication
Public Sub Dispose() Implements IHttpModule.Dispose
End Sub
Dim myUserManager As UserManager
Public Sub Init(ByVal context As HttpApplication) Implements IHttpModule.Init
_context = context
myUserManager = New UserManager
End Sub
Public Sub OnAuthorizeRequest(ByVal source As Object, ByVal e As EventArgs) Handles _context.PostAuthenticateRequest
Const networkAuthenticationRequiredStatusCode As Integer = 511
Try
If IsVideoUrl() Then
If _context.User Is Nothing Then
LogManager.WriteMessage("_context.User is nothing:", "")
End If
Dim userId As Integer = myUserManager.GetUserIdByUserName(_context.User.Identity.Name)
If (UserRequiresAuthorization(userId)) Then
If Not UserIsAssignedToCourseContainingVideo(userId) Then
LogAccessDeniedMessage()
_context.Response.StatusCode = networkAuthenticationRequiredStatusCode
_context.Response.ClearContent()
_context.Response.Write("UnAuthorized User")
_context.Response.End()
End If
End If
End If
Catch ex As Exception
LogManager.WriteException(ex, "")
End Try
End Sub
End Class
To ensure that _context.User is set add the runAllManagedModulesForAllRequests="true" to the modules section of the web.config like below.
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<remove name="ScriptModule" />
<remove name="RadUploadModule" />
<remove name="RadCompression" />
<remove name="VideoSecurityModule" />
<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add name="RadUploadModule" type="Telerik.Web.UI.RadUploadHttpModule" preCondition="integratedMode,runtimeVersionv2.0" />
<add name="RadCompression" type="Telerik.Web.UI.RadCompression" preCondition="integratedMode,runtimeVersionv2.0" />
<add name="VideoSecurityModule" type="LMS.VideoSecurityModule"/>
</modules>
Related
I'm trying to get a handler to be called for the site root request by the browser, i.e. http://my.example.com. Given the code below, if I call /Test, the handler works as expected, but without that, I get the HTTP Error 403.14 - Forbidden (directory browsing isn't allowed).
Windows Server 2012-R2 / IIS 8.5
There is no MVC involved
ScriptModule-4.0 module is inherited so extensionless works
Similar to this question from 2012 that was never properly answered
Generic handler is given as an example...could also be a Soap Web Service
I've tried various combinations of slashes and asterisks for the handler path without success.
Generic handler:
Public Class Test
Implements IHttpHandler
Public Sub ProcessRequest(Context As HttpContext) _
Implements IHttpHandler.ProcessRequest
With New StringBuilder
.AppendLine("<html>")
.AppendLine("<head>")
.AppendLine("<title>Test</title>")
.AppendLine("</head>")
.AppendLine("<body>")
.AppendLine("<p>Hello World</p>")
.AppendLine("</body>")
.AppendLine("</html>")
Context.Response.Write(.ToString)
End With
End Sub
End Class
...and in web.config I have the following:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation strict="false" explicit="true" debug="true" targetFramework="4.5.2" />
<customErrors mode="Off" />
<authentication mode="Windows" />
<httpRuntime targetFramework="4.5.2" />
</system.web>
<system.webServer>
<handlers>
<add verb="*" name="Test" type="MyApp.Test" path="Test" />
</handlers>
<defaultDocument enabled="true">
<files>
<clear />
<add value="Test" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
The solution I came up with, but I'm open to other ideas.
In web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation strict="false" explicit="true" debug="true" targetFramework="4.5.2" />
<customErrors mode="Off" />
<authentication mode="Windows" />
<httpRuntime targetFramework="4.5.2" />
<!-- Required for Web Services via Handlers -->
<webServices>
<protocols>
<add name="HttpGet" />
<add name="HttpPost" />
</protocols>
</webServices>
</system.web>
<system.webServer>
<handlers>
<add verb="GET,POST" name="Test" type="MyApp.Test" path="Test" />
</handlers>
<modules>
<add name="AppModule" type="MyApp.AppModule" />
</modules>
<defaultDocument enabled="false" />
<directoryBrowse enabled="false" />
</system.webServer>
</configuration>
And then added the AppModule class where I evaluate HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath and do a HttpContext.Current.RewritePath so the handler defined above will pick it up.
my.example.com
my.example.com/AnyFolder/MyApplication
Matching for "~/" works if the web app is at the site root in IIS or is set up as an app within a site:
Public Class AppModule
Implements IHttpModule
Friend WithEvents WebApp As HttpApplication
Public Sub Init(ByVal HttpApplication As HttpApplication) _
Implements IHttpModule.Init
WebApp = HttpApplication
End Sub
Private Sub WebApp_BeginRequest(sender As Object, e As EventArgs) _
Handles WebApp.BeginRequest
With HttpContext.Current
If .Request.AppRelativeCurrentExecutionFilePath = "~/" Then .RewritePath("~/Test")
End With
End Sub
Public Sub Dispose() _
Implements IHttpModule.Dispose
Throw New NotImplementedException()
End Sub
End Class
I just created a basic Web Controller in my project. I hit debug and try to browse to /api/duedate and I get a 404. I am new to controllers and have been looking at every tutorial I can find. None of them say I need to add anything more to get this to work.
Imports System.Net
Imports System.Web.Http
Public Class DueDateController
Inherits ApiController
' GET api/duedate
Public Function GetValues() As IEnumerable(Of String)
Return New String() {"value1", "value2"}
End Function
' GET api/duedate/5
Public Function GetValue(ByVal id As Integer) As String
Return "value"
End Function
' POST api/duedate
Public Sub PostValue(<FromBody()> ByVal value As String)
End Sub
' PUT api/duedate/5
Public Sub PutValue(ByVal id As Integer, <FromBody()> ByVal value As String)
End Sub
' DELETE api/duedate/5
Public Sub DeleteValue(ByVal id As Integer)
End Sub
End Class
My web.config looks like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
<add key="webPages:Version" value="2.0"/>
</appSettings>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true" />
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers></system.webServer>
</configuration>
I believe you need to add a route.
Routing in VB
If you read the last comment in this thread it should show you how to add routing to your app.
To help anyone else out and to simplify having to read through that long post. You need to create and modify your global.asax file to include this:
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
RouteTable.Routes.MapHttpRoute("WebApi1",
"api/{controller}/{id}",
defaults:=New With {.id = System.Web.Http.RouteParameter.Optional})
End Sub
Update: Problem solved. Read on.
Any idea why it's apparently not possible anymore to add custom IHttpModules?
My question is related to: HttpModule.Init - safely add HttpApplication.BeginRequest handler in IIS7 integrated mode
However this question is rather old, unanswered and has no SharePoint context. I CAN add my HttpModule to any standard ASP.NET WebForms page.
SharePoint is being hosted in IIS 8. AppPool runs in Integrated Mode. Framework level is 4.0+.
namespace My.Namespace
{
using System;
using System.Web;
public class CustomHttpModule : IHttpModule
{
private static readonly object mutex = new object();
private static bool _isInitialized;
public void Init(HttpApplication context)
{
if (!_isInitialized)
{
lock (mutex)
{
if (_isInitialized) return;
context.BeginRequest += BeginRequest;
_isInitialized = true;
}
}
}
private void BeginRequest(object sender, EventArgs e)
{
}
public void Dispose()
{
}
}
}
Result:
[NullReferenceException: Object reference not set to an instance of an object.]
System.Web.PipelineModuleStepContainer.GetEventCount(RequestNotification notification, Boolean isPostEvent) +30
System.Web.PipelineStepManager.ResumeSteps(Exception error) +1098
System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb) +135
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +604
The web.config looks as follows:
<system.webServer>
<!-- further elements omitted -->
<modules runAllManagedModulesForAllRequests="true">
<remove name="AnonymousIdentification" />
<remove name="FileAuthorization" />
<remove name="Profile" />
<remove name="WebDAVModule" />
<remove name="Session" />
<add name="SPNativeRequestModule" preCondition="integratedMode" />
<add name="SPRequestModule" preCondition="integratedMode" type="Microsoft.SharePoint.ApplicationRuntime.SPRequestModule, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add name="SharePoint14Module" preCondition="integratedMode" />
<add name="StateServiceModule" type="Microsoft.Office.Server.Administration.StateModule, Microsoft.Office.Server, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="PublishingHttpModule" type="Microsoft.SharePoint.Publishing.PublishingHttpModule, Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="DesignHttpModule" preCondition="integratedMode" type="Microsoft.SharePoint.Publishing.Design.DesignHttpModule, Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="FederatedAuthentication" type="Microsoft.SharePoint.IdentityModel.SPFederationAuthenticationModule, Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="SessionAuthentication" type="Microsoft.SharePoint.IdentityModel.SPSessionAuthenticationModule, Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="SPWindowsClaimsAuthentication" type="Microsoft.SharePoint.IdentityModel.SPWindowsClaimsAuthenticationHttpModule, Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="SPApplicationAuthentication" type="Microsoft.SharePoint.IdentityModel.SPApplicationAuthenticationModule, Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="Session" type="System.Web.SessionState.SessionStateModule" />
<add name="CustomModule" type="My.Namespace.CustomHttpModule, My.Namespace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=066b2229567b6747" />
</modules>
<!-- further elements omitted -->
</system.webServer>
As soon as I don't attach to the BeginRequest event anymore the page works again. But obviously my http module is rendered useless.
Edit 2013.09.19: Init() is being called twice upon application start. If I attach my event only on the second call the application works but the event doesn't fire.
Edit 2013.09.20: Problem presumably solved. The fact that my Init() method is triggered twice (and no Dispose() is called in between) led me to the assumption there might actually be two co-existing instances of my IHttpModule. And while my previous observation showed that the second instance can have the event attached (not firing, but no negative impact on the application as well) - it apparently is not true vice versa (which is the case with my static _isInitialized "lock").
**So both instances of the IHttpModule need to have the same "configuration" (eventhandlers attached). It is totally normal to have more than one HttpApplication instance running. That's something ASP.NET (or IIS) does internally for optimization purposes. That's the key thing to remember :)
Problem solved. Edited question. See Edit 2013.09.20.
I've been working on this site on VS Studio for Web 2012. Most of it is HTML and ASP, but I've included a DayPilot calendar that I downloaded from SourceForge. I, apparently, must DataBind the calendar to my SQL server, so that users can login and set aside times for themselves on the calendar. I've used just about every recommended code I can find on the Net, but none seem to work on the Calendar page.
Here is the aspx page and the aspx.vb page codes:
(aspx page)
<%# Page Title="" Language="VB" MasterPageFile="~/MasterPage.master" AutoEventWireup="false" CodeFile="calendarpg.aspx.vb" Inherits="_Default" %>
<%# Register Assembly="DayPilot" Namespace="DayPilot.Web.Ui" TagPrefix="DayPilot" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
<script type="text/javascript" src="<%=ResolveUrl("~/Scripts/DayPilot/calendar.js")%>">
</script>
<style type="text/css">
.auto-style8 {
font-size: large;
}
</style>
<link type="text/css" rel="stylesheet" href="<%=ResolveUrl("~/Themes/themes.css")%>" />
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
dbo.BasicData
<DayPilot:DayPilotNavigator ID="DayPilotNavigator1" runat="server" />
<DayPilot:DayPilotCalendar ID="DayPilotCalendar1" runat="server" Days="7" EventMoveJavaScript="alert('eventMove(e.start(), newEnd')" BackColor="#CCFFFF" DataStartField="null"></DayPilot:DayPilotCalendar>
<DayPilot:DayPilotScheduler ID="DayPilotScheduler1" runat="server">
</DayPilot:DayPilotScheduler>
<br />
<h1><strong>Scheduling</strong></h1>
<span class="auto-style8">Requests are made via the Calendar for each of the respective Sandboxes.
A minimum of 24-hour notice is rquired when making a request to allow
time for preparation of a Sandbox,
<br />
time zone differences, and to resolve any
scheduling conflicts.
<br />
<br />
The process for booking is similar to booking a conference room.
<br />
<br />
Choose a day and time that is open, for the Sandbox you're interested in using,
then choose the open hours that work best for your schedule. </span>
</asp:Content>
(aspx.vb page)
Partial Class _Default
Inherits System.Web.UI.Page
'Declaration
Public Event DataBinding As EventHandler
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
DayPilotCalendar1.DataSource = getData()
DataBind()
End Sub
Public Function getData() As Data.DataTable
Dim dt As Data.DataTable
dt = New Data.DataTable
dt.Columns.Add("start", GetType(DateTime))
dt.Columns.Add("end", GetType(DateTime))
dt.Columns.Add("name", GetType(String))
dt.Columns.Add("id", GetType(String))
Dim dr As Data.DataRow = dt.NewRow()
dr("id") = 0
dr("start") = Convert.ToDateTime("15:50")
dr("end") = Convert.ToDateTime("15:55")
dr("name") = "Event 1"
dt.Rows.Add(dr)
dr = dt.NewRow()
dr("id") = 1
dr("start") = Convert.ToDateTime("16:00")
dr("end") = Convert.ToDateTime("17:00")
dr("name") = "Event 2"
dt.Rows.Add(dr)
dr = dt.NewRow()
dr("id") = 2
dr("start") = Convert.ToDateTime("16:15")
dr("end") = Convert.ToDateTime("18:45")
dr("name") = "Event 3"
dt.Rows.Add(dr)
Return dt
End Function
End Class
(this is my Web.Config page as it stands now)
<using System.Web.Configuration; />
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<connectionStrings>
<add name="ConnStringDb1" connectionString="DataSource=Win08-SDBX1\SQLExpress;Initial Catalog=aspnetdb;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.5">
<assemblies>
<add assembly="Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
<add assembly="Microsoft.VisualC, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
<add assembly="Microsoft.VisualStudio.Tools.Applications.Adapter.v9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
<add assembly="Microsoft.VisualStudio.Tools.Applications.DesignTime.v9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
<add assembly="Microsoft.VisualStudio.Tools.Applications.Hosting.v9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
<add assembly="Microsoft.VisualStudio.Tools.Applications.ProgrammingModel, Version=9.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
<add assembly="Microsoft.VisualStudio.Tools.Applications.Runtime.v9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
<add assembly="System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
</assemblies>
</compilation>
<httpRuntime targetFramework="4.5" />
<pages>
<controls>
<add tagPrefix="ajaxToolkit" assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" />
</controls>
</pages>
</system.web>
</configuration>
If any of that makes sense, or you see where I'm going wrong, please share or correct my coding. Thank you!
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
DayPilotCalendar1.DataSource = getData()
DataBind()
End Sub
This need to be
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
DayPilotCalendar1.DataSource = getData()
DayPilotCalendar1.DataBind()
End Sub
Can we see the Databind function that is called by PageLoad?
I had an issue similar to this when I was working on a C# asp.net application. I created a method to bind the data from a dataset that contained a table of cards. When loading the table "NullReferenceException was unhandled by user code" was thrown and upon looking at the table I could see that a null value was being held.
When you are debugging and the exception is thrown, what is being shown as the held value of the data table?
If it is null then your table is not referring to an object.
I created a File Cleanup Provider that is inherits system.web.management.webeventprovider.
Public Class FileCleanupProvider
Inherits System.Web.Management.WebEventProvider
Private Const StateFIleFolderPath As String = "StateData/"
Public Overrides Sub Initialize(ByVal name As String, ByVal config As System.Collections.Specialized.NameValueCollection)
MyBase.Initialize(name, config)
End Sub
Public Overrides Sub Flush()
' not required
End Sub
Public Overrides Sub ProcessEvent(ByVal raisedEvent As System.Web.Management.WebBaseEvent)
Dim DateTimeRaised As DateTime = raisedEvent.EventTime
' Remove files
Dim FilePath As String = IO.Path.Combine(HttpRuntime.AppDomainAppPath, StateFIleFolderPath)
For Each FileName In IO.Directory.GetFiles(FilePath)
If (DateTimeRaised - IO.File.GetCreationTime(FileName)) > TimeSpan.FromHours(6) Then
IO.File.Delete(FileName)
End If
Next
End Sub
Public Overrides Sub ShutDown()
'Clean up on shut down
Dim FilePath As String = IO.Path.Combine(HttpRuntime.AppDomainAppPath, StateFIleFolderPath)
For Each FileName In IO.Directory.GetFiles(FilePath)
IO.File.Delete(FileName)
Next
End Sub
End Class
And I configure in web.config this
<healthMonitoring enabled="true" heartbeatInterval="5">
<providers>
<add name="FileCleanupProvider" type="System.Web.Management.WebEventProvider"/>
</providers>
<profiles>
<remove name="Default"/>
<add name="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom=""/>
</profiles>
<eventMappings>
<remove name="Heartbeats"/>
<add name="Heartbeats" type="System.Web.Management.WebHeartbeatEvent,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" startEventCode="0" endEventCode="2147483647" />
</eventMappings>
<!--<eventMappings>
<add name="FileCleanupEvent" type="System.Web.Management.WebHeartbeatEvent" startEventCode="0" endEventCode="2147483647"/>
</eventMappings>-->
<rules>
<clear/>
<add name="FileCleanupRule" eventName="Heartbeats" provider="FileCleanupProvider" profile="Default"/>
</rules>
</healthMonitoring>
But I got one problem that.
How can I solve that?
You need to specify your class in the configuration:
<add name="FileCleanupProvider" type="YourNameSpace.FileCleanupProvider,AssemblyName,Version=0.0.0.0,Culture=neutral,PublicKeyToken=PublicKeyHere"/>
The .NET is creating instance of the class on the fly, so the class must be "valid".