.NET Maui iOS - System.PlatformNotSupportedException: 'Operation is not supported on this platform.' Google.Apis.Auth.OAuth2 - xamarin.ios

This Library / code works fine in Xamarin Forms latest. I'm working on bringing an App over to .NET Maui and am receiving this error. Is there something about .NET Maui HTTP that is less supported than Xamarin iOS?
at System.Net.Http.NSUrlSessionHandler.get_SupportsRedirectConfiguration()
at System.Reflection.RuntimeMethodInfo.Invoke(Object , BindingFlags , Binder , Object[] , CultureInfo )
--- End of stack trace from previous location ---
at System.Net.Http.HttpClientHandler.InvokeNativeHandlerMethod(String , Object[] )
at System.Net.Http.HttpClientHandler.GetSupportsRedirectConfiguration()
at System.Net.Http.HttpClientHandler.get_SupportsRedirectConfiguration()
at Google.Apis.Http.HttpClientFactory.CreateAndConfigureClientHandler()
at Google.Apis.Http.HttpClientFactory.CreateHandler(CreateHttpClientArgs args)
at Google.Apis.Http.HttpClientFactory.CreateHttpClient(CreateHttpClientArgs args)
at Google.Apis.Auth.OAuth2.ServiceCredential..ctor(Initializer initializer)
at Google.Apis.Auth.OAuth2.ServiceAccountCredential..ctor(Initializer initializer)
at Google.Apis.Auth.OAuth2.DefaultCredentialProvider.CreateServiceAccountCredentialFromParameters(JsonCredentialParameters credentialParameters)
at Google.Apis.Auth.OAuth2.DefaultCredentialProvider.CreateDefaultCredentialFromParameters(JsonCredentialParameters credentialParameters)
at Google.Apis.Auth.OAuth2.DefaultCredentialProvider.CreateDefaultCredentialFromJson(String json)
at Google.Apis.Auth.OAuth2.GoogleCredential.FromJson(String json)
Code:
string content = File.ReadAllText("secret.json");
var credential = GoogleCredential.FromJson(content).CreateScoped(new string[] { SheetsService.Scope.Spreadsheets });
new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential
});

Related

AspNetCore.OData 7.1.0 "$search" Query Option not working

I have created a .Net Core 2 API using OData 4.0 (part of AspNetCore.OData 7.1.0).
Everything, except the "$search", seems to work.
The documentation says it should work.
The following requests I tested didn't work:
http://host/service/Products?$search=banana
http://host/service/Products?$search="banana"
http://host/service/$all?$search="banana"
error message:
{"message":"The query parameter 'Specified argument was out of the range of valid values.\r\nParameter name: $search' is not supported.","exceptionMessage":"Specified argument was out of the range of valid values.\r\nParameter name: $search","exceptionType":"System.ArgumentOutOfRangeException","stackTrace":" at Microsoft.AspNet.OData.EnableQueryAttribute.ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.<>c__DisplayClass1_0.<OnActionExecuted>b__3(ODataQueryContext queryContext)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, Func`2 modelFunction, IWebApiRequestMessage request, Func`2 createQueryOptionFunction)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.OnActionExecuted(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, IWebApiRequestMessage request, Func`2 modelFunction, Func`2 createQueryOptionFunction, Action`1 createResponseAction, Action`3 createErrorAction)"}
The following requests I tested worked:
http://host/service/$metadata/
http://host/service/Products?$filter=contains(name, "banana")
My code:
Configure app (defined in Startup.cs):
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
// Cors
app.UseCors(builder => builder
.WithOrigins("*")
.AllowAnyHeader()
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowCredentials()
);
//app.UseHttpsRedirection();
app.UseMvc(routeBuilder =>
{
routeBuilder.MapODataServiceRoute("odata", $"service/", GetEdmModel());
routeBuilder.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
routeBuilder.EnableDependencyInjection();
});
}
EdmModel (defined in Startup.cs):
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Product");
builder.EntitySet<Producer>("Producer");
builder.EntitySet<Consumer>("Consumer");
return builder.GetEdmModel();
}
.Net Core 2.2 Api "Get" (ProductsController.cs):
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable<Product>))]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[EnableQuery]
public async Task<ActionResult<Product>> Get()
{
var dbResponse = _context.Products.AsQueryable();
return this.OK(dbresponse);
}

Xamarin.UITest System.Xml.XmlException

I am creating a UI test for my Xamarin.Forms app. When I try to start the first test for iOS project, I get a System.Xml.XmlException (detailed below). This basic test should be working, right?
Update: If I uninstall the app from the simulator, the test runs for the first time. After that I keep getting the exception for all following runs.
I am using Xamarin Studio (6.1.3 build 19) and
Xamarin.UITest package (2.0.5)
namespace UITest
{
[TestFixture (Platform.Android)]
[TestFixture (Platform.iOS)]
public class Tests
{
IApp app;
Platform platform;
public Tests (Platform platform)
{
this.platform = platform;
}
[SetUp]
public void BeforeEachTest ()
{
app = AppInitializer.StartApp (platform);
}
[Test]
public void AppLaunches ()
{
try {
app.WaitForElement ("Waiting for fake element", "Timeout", new TimeSpan (0, 0, 20));
} catch (TimeoutException ex) {
int i = 5;
}
app.Screenshot ("Welcome screen.");
app.Tap ("TestButton");
app.Screenshot ("New test screen.");
}
}
public class AppInitializer
{
public static IApp StartApp (Platform platform)
{
if (platform == Platform.Android) {
return ConfigureApp
.Android
.StartApp ();
}
return ConfigureApp
.iOS
.Debug ()
.EnableLocalScreenshots ()
.StartApp ();
}
}
}
Exception details:
SetUp : System.Xml.XmlException : '', hexadecimal value 0x01, is an invalid character. Line 11, position 11.
Stack trace:
at Xamarin.UITest.iOS.iOSAppLauncher.LaunchAppLocal (Xamarin.UITest.Configuration.IiOSAppConfiguration appConfiguration, Xamarin.UITest.Shared.Http.HttpClient httpClient, System.Boolean clearAppData) [0x0020a] in <e747267e258a4a668973c7ca7e9014a8>:0
at Xamarin.UITest.iOS.iOSAppLauncher.LaunchApp (Xamarin.UITest.Configuration.IiOSAppConfiguration appConfiguration, Xamarin.UITest.Shared.Http.HttpClient httpClient, Xamarin.UITest.TestCloud.TestCloudiOSAppConfiguration testCloudAppConfiguration, Xamarin.UITest.Shared.Http.HttpClient testCloudWsClient, Xamarin.UITest.Shared.Http.HttpClient xtcServicesClient, System.Boolean testCloudUseDeviceAgent) [0x0007a] in <e747267e258a4a668973c7ca7e9014a8>:0
at Xamarin.UITest.iOS.iOSApp..ctor (Xamarin.UITest.Configuration.IiOSAppConfiguration appConfiguration) [0x00302] in <e747267e258a4a668973c7ca7e9014a8>:0
at Xamarin.UITest.Configuration.iOSAppConfigurator.StartApp (Xamarin.UITest.Configuration.AppDataMode appDataMode) [0x00017] in <e747267e258a4a668973c7ca7e9014a8>:0
at UITest.AppInitializer.StartApp (Xamarin.UITest.Platform platform) [0x0001f] in /Users/samg/projects/myapp-mobile/myapp-mobile-2/UITest/AppInitializer.cs:38
at UITest.Tests.BeforeEachTest () [0x00008] in /Users/samg/projects/myapp-mobile/myapp-mobile-2/UITest/Tests.cs:26
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in /private/tmp/source-mono-4.6.0/bockbuild-mono-4.6.0-branch/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/corlib/System.Reflection/MonoMethod.cs:305
I know this is an old question, however it might help others. I experienced the same problem described above and solved it by resetting the iOS simulator.
One way to accomplish this is to take the following steps:
Make sure the iPhone/iPad simulator is running;
Go to the top-menu and select "iOS Simulator" -> "Reset Content and Settings..."

Owin hosted web app using Token authentication

I am trying to create an owin web app using token authentication, my startup does not have any special setup like the example in
https://github.com/NancyFx/Nancy/wiki/Token-Authentication
public class Bootstrapper : DefaultNancyBootstrapper
{
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
TokenAuthentication.Enable(pipelines, new TokenAuthenticationConfiguration(container.Resolve<ITokenizer>()));
}
}
mine is simply
public void Configuration(IAppBuilder app)
{
app.UseNancy();
}
I have the module defined like
public HomeModule(ITokenizer tokenizer)
{
Post["/login"] = _ =>
{
DefaultUserIdentityResolver resolver = new DefaultUserIdentityResolver();
//var userName = (string)this.Request.Form.Username;
//var password = (string)this.Request.Form.Password;
var claims = new List<string> { "admin", "poweruser" };
var userIdentity = resolver.GetUser("ross", claims, Context);
if (userIdentity == null)
{
return HttpStatusCode.Unauthorized;
}
var token = tokenizer.Tokenize(userIdentity, Context);
return new
{
Token = token,
};
};
}
Not much just yet I know but when when I get to tokenize I get an exception of the type Nancy.ErrorHandling.RouteExecutionEarlyExitException which really doesnt have anything in the message or stack trace to indicate the issue.
I am currently hosting over http in casini on .NET 4.5.1
Any pointers would be appreciated
Update:
Message is:
Exception of type 'Nancy.ErrorHandling.RouteExecutionEarlyExitException' was thrown.
Stack trace is:
at Nancy.Authentication.Token.Tokenizer.Tokenize(IUserIdentity userIdentity, NancyContext context)
at Samaritan.Hosting.HttpServices.HomeModule.<>c__DisplayClass11.<.ctor>b__7(Object _) in c:\src\DukeSoftware\Samaritan\Main\Samaritan.Hosting.HttpServices\HomeModule.cs:line 39
at CallSite.Target(Closure , CallSite , Func`2 , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
at Nancy.Routing.Route.<>c__DisplayClass4.<Wrap>b__3(Object parameters, CancellationToken context)
I tried setting up the startup.cs like this
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseNancy();
}
}
public class Bootstrapper : DefaultNancyBootstrapper
{
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
TokenAuthentication.Enable(pipelines, new TokenAuthenticationConfiguration(container.Resolve<ITokenizer>()));
}
}
but I got the following exception
{"Located multiple bootstrappers:\r\n - Samaritan.Hosting.HttpServices.BootStarapper\r\n - Samaritan.Hosting.HttpServices.Bootstrapper\r\n\r\nEither remove unused bootstrapper types or specify which type to use."}
So I removed the bootsrapper and just left Startup. An instantiated tokenizer seems to be passed into the module when you declare the constructor public HomeModule(ITokenizer tokenizer)
So I didnt think the creation of the tokenizer was a problem
did you find fix?
I'm encountering the same exception. It's because I have 2 EXE files in the same directory having child of 'DefaultNancyBootstrapper' class.
I gotta use old Nancy v1.0. so it seems there's no other way but to use 'DefaultNancyBootstrapper' in only one place.

Exception thrown when using Glimpse and Postal

I'm just starting to use Glimpse with my MVC5 project and have run into an issue when I use Postal to send an email without disabling Glimpse. I've been able to narrow it down to an issue with both packages - it doesn't occur if the Glimpse cookie has not been turned on.
In Fiddler, I checked the difference between the two. When it threw the exception, the cookie was
glimpsePolicy=On
when it worked (Glimpse was off) there were two cookies
glimpseId=FBar; glimpsePolicy=
The exception I get is
System.ArgumentNullException: Value cannot be null.
Parameter name: controllerContext
at System.Web.Mvc.ChildActionValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
at Castle.Proxies.Invocations.ValueProviderFactory_GetValueProvider.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Glimpse.Core.Extensibility.ExecutionTimer.Time(Action action)
at Glimpse.Core.Extensibility.AlternateMethod.NewImplementation(IAlternateMethodContext context)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.ValueProviderFactoryProxy.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.ControllerBase.get_ValueProvider()
at Glimpse.Mvc.Message.ActionMessageExtension.AsActionMessage[T](T message, ControllerBase controller)
at Glimpse.Mvc.AlternateType.ViewEngine.FindViews.PostImplementation(IAlternateMethodContext context, TimerResult timerResult)
at Glimpse.Core.Extensibility.AlternateMethod.NewImplementation(IAlternateMethodContext context)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.IViewEngineProxy.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache)
at System.Web.Mvc.ViewEngineCollection.<>c__DisplayClass6.<FindView>b__4(IViewEngine e)
at System.Web.Mvc.ViewEngineCollection.Find(Func`2 lookup, Boolean trackSearchedPaths)
at System.Web.Mvc.ViewEngineCollection.Find(Func`2 cacheLocator, Func`2 locator)
at Postal.EmailViewRenderer.Render(Email email, String viewName)
at Postal.EmailService.Send(Email email)
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid1[T0](CallSite site, T0 arg0)
at System.Web.Mvc.ActionMethodDispatcher.<>c__DisplayClass1.<WrapVoidAction>b__0(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__36(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
at Castle.Proxies.Invocations.AsyncControllerActionInvoker_EndInvokeActionMethod.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Glimpse.Mvc.AlternateType.AsyncActionInvoker.EndInvokeActionMethod.NewImplementation(IAlternateMethodContext context)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.AsyncControllerActionInvokerProxy.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3c()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass45.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3e()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass30.<BeginInvokeActionMethodWithFilters>b__2f(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<>c__DisplayClass28.<BeginInvokeAction>b__19()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass1e.<BeginInvokeAction>b__1b(IAsyncResult asyncResult)
I created a quick action to test it. The controller code is:
public void TestEmailExt()
{
var confirmationToken = "ConfirmationToken";
var Phone1 = "**********";
dynamic email = new Email("RegEmail");
email.To = "**#gmail.com";
email.UserName = "UserName";
email.ConfirmationToken = confirmationToken;
email.Phone = Extensions.Right(Phone1, 4);
if (email.To.Contains("#mydomain"))
email.From = INTERNAL_EMAIL_FROM;
else
email.From = EXTERNAL_EMAIL_FROM;
email.Send();
}
The reason this fails is because the Postal library creates its own HttpContext instance while rendering the email view as the decompiled CreateControllerContext method inside Postal's EmailViewRenderer class shows:
private ControllerContext CreateControllerContext()
{
HttpContextWrapper httpContextWrapper = new HttpContextWrapper(new HttpContext(new HttpRequest("", this.UrlRoot(), ""), new HttpResponse(TextWriter.Null)));
RouteData routeData = new RouteData();
routeData.Values["controller"] = (object) this.EmailViewDirectoryName;
return new ControllerContext(new RequestContext((HttpContextBase) httpContextWrapper, routeData), (ControllerBase) new EmailViewRenderer.StubController());
}
This means that the setup that Glimpse does at BeginRequest is completely removed, while the hooks are still in place to intercept MVC related calls.
We've had a similar issue where I gave a similar response to why this is not working.
UPDATE :
I mentioned above that a similar issue had been reported previously, but while I was trying to find a more appropriate solution, it seemed that this case is slightly different in that respect that the other similar issue actually executes a controller with the freshly created context resulting in a NullReferenceException in Glimpse specific code, while here we get a NullReferenceException inside MVC specific code, albeit triggered by Glimpse.
System.ArgumentNullException: Value cannot be null.
Parameter name: controllerContext
at System.Web.Mvc.ChildActionValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
And the exception we get here is because the ControllerContext property on the StubController instance (created inline) is null, which would normally be set when executing the controller (which is not the case here).
So the workaround that I proposed below still applies, but can be avoided if the code of the CreateControllerContext() above is slightly modified:
private ControllerContext CreateControllerContext()
{
HttpContextWrapper httpContextWrapper = new HttpContextWrapper(new HttpContext(new HttpRequest("", this.UrlRoot(), ""), new HttpResponse(TextWriter.Null)));
RouteData routeData = new RouteData();
routeData.Values["controller"] = (object) this.EmailViewDirectoryName;
// MODIFIED
var stubController = new EmailViewRenderer.StubController();
var controllerContext = new ControllerContext(new RequestContext(httpContextWrapper, routeData), stubController);
stubController.ControllerContext = controllerContext;
return controllerContext;
}
I've created an issue for this on the Postal issue tracker
END OF UPDATE
I think the best solution, for now, is to disable Glimpse while calling into Postal and restore normal Glimpse behavior back again afterwards. We might include this one way or the other into the Glimpse Core library in one of the upcoming releases as it seems that disabling Glimpse during a specific part of the request processing logic doesn't seem to be that uncommon, but for now the following snippet might help you (beware it makes use of a Glimpse internal key which is not guaranteed to be there in an upcoming release)
public class GlimpseSuppressionScope : IDisposable
{
private const string GlimpseRequestRuntimePermissionsKey = "__GlimpseRequestRuntimePermissions";
private readonly HttpContext currentHttpContext;
private readonly RuntimePolicy? currentRuntimePolicy;
private bool disposed;
public GlimpseSuppressionScope(HttpContext currentHttpContext)
{
if (currentHttpContext == null)
{
throw new ArgumentNullException("currentHttpContext");
}
this.currentHttpContext = currentHttpContext;
this.currentRuntimePolicy = this.currentHttpContext.Items[GlimpseRequestRuntimePermissionsKey] as RuntimePolicy?;
this.currentHttpContext.Items[GlimpseRequestRuntimePermissionsKey] = RuntimePolicy.Off;
}
~GlimpseSuppressionScope()
{
this.Dispose(false);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
if (this.currentHttpContext != null)
{
this.currentHttpContext.Items.Remove(GlimpseRequestRuntimePermissionsKey);
if (this.currentRuntimePolicy.HasValue)
{
this.currentHttpContext.Items[GlimpseRequestRuntimePermissionsKey] = this.currentRuntimePolicy.Value;
}
}
}
this.disposed = true;
}
}
}
which you can then use in your controller action method as shown below:
public void TestEmailExt()
{
using (new GlimpseSuppressionScope(System.Web.HttpContext.Current))
{
var confirmationToken = "ConfirmationToken";
var Phone1 = "**********";
dynamic email = new Email("RegEmail");
email.To = "**#gmail.com";
email.UserName = "UserName";
email.ConfirmationToken = confirmationToken;
email.Phone = Extensions.Right(Phone1, 4);
if (email.To.Contains("#mydomain"))
email.From = INTERNAL_EMAIL_FROM;
else
email.From = EXTERNAL_EMAIL_FROM;
email.Send();
}
}

NullReferenceException when returning Blob stream in MVC after updating to Storage 2.1.0.3

I have several Actions in my MVC Controllers that return an Azure blob by passing a blob stream into a FileResult. Like this:
public FileResult DownloadReport(string Id)
{
// Look up model
string fileName = messenger.ReportTitle(Id);
// Get a reference to the blob
CloudBlockBlob mainReportBlob = cloudBlobContainer.GetBlockBlobReference(Id);
// Return as a FileResult
using (var reportReader = mainReportBlob.OpenRead())
{
return File(reportReader , "application/pdf", fileName );
}
}
I recently updated my Azure Storage library to the latest and started receiving the following exceptions:
System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=Microsoft.WindowsAzure.Storage
StackTrace:
at Microsoft.WindowsAzure.Storage.Blob.BlobReadStreamBase.ConsumeBuffer(Byte[] buffer, Int32 offset, Int32 count) in e:\projects\azure-sdk-for-net\microsoft-azure-api\Services\Storage\Lib\Common\Blob\BlobReadStreamBase.cs:line 222
at Microsoft.WindowsAzure.Storage.Blob.BlobReadStream.Read(Byte[] buffer, Int32 offset, Int32 count) in e:\projects\azure-sdk-for-net\microsoft-azure-api\Services\Storage\Lib\DotNetCommon\Blob\BlobReadStream.cs:line 72
at System.Web.Mvc.FileStreamResult.WriteFile(HttpResponseBase response)
at System.Web.Mvc.FileResult.ExecuteResult(ControllerContext context)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
The error seems to be coming from within the Azure libraries themselves. Any ideas?
So after stepping thru things with a decompiler, I found the BlobReadStreamBase.Dispose() method was being called before it had been read. Digging further, it seems that returning File() from a controller doesn't actually read the stream, but simply passes it up to the rest of MVC to deal with it.
What this means is that my using() block was closing the Blob stream before MVC could read it further down the pipeline. I changed my Action to this:
public FileResult DownloadReport(string Id)
{
// Look up model
string fileName = messenger.ReportTitle(Id);
// Get a reference to the blob
CloudBlockBlob mainReportBlob = cloudBlobContainer.GetBlockBlobReference(Id);
// Return as a FileResult, DON'T place in a using() block or it will be closed early
var reportReader = mainReportBlob.OpenRead();
return File(reportReader , "application/pdf", fileName );
}
This works. Furthermore, I set a breakpoint in my decompiler and BlobReadStreamBase.Dispose() is being called later, so presumably MVC is cleaning things up further down the pipeline.
I'm not sure why this worked before, as it shouldn't have. Maybe a bug that was fixed in the Azure libraries?

Resources