OpenXML Excel Local Environment vs AWS Lambda - aws-lambda

In the local environment (Windows 7, Kestrel, AspNetCore 2.0) everything works great no errors. However, when I deploy to AWS as a LAMBDA function using API Gateway I get the bellow error.
[HttpPost]
[Route("Temp")]
public IActionResult PostTest(IFormFile file)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Open(file.OpenReadStream(), false))
{
}
return Ok();
}
Unknown error responding to request: FileFormatException:
System.IO.FileFormatException: File contains corrupted data.
at System.IO.Packaging.ZipPackage..ctor(Stream s, FileMode packageFileMode, FileAccess packageFileAccess)
at System.IO.Packaging.Package.Open(Stream stream, FileMode packageMode, FileAccess packageAccess)
at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.OpenCore(Stream stream, Boolean readWriteMode)
at DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(Stream stream, Boolean isEditable, OpenSettings openSettings)
at api.Controllers.SKUController.Post2Async(IFormFile file) in \lambda\api\Controllers\SKUController.cs:line 72
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__12.MoveNext()
I am able to post the excel just fine to AWS, (And even read it using system io) but the method for SpreedsheetDocument.Open is not working. (Also checked on that I can write a text file to a temp directory that seemed to work also)
Microsoft.AspNetCore.All 2.0.3 & NETStandard.Library 2.0.1
System.IO.Packaging 4.4.1
DocumentFormat.OpenXml 2.8.1

Check to see if the excel file you are attempting to open is password protected. If it is, remove the password protection, re save it and try to read the file again.
I found an MSDN post where users were experiencing the same error. After their research it was determined that the File contains corrupted data. exception can be caused by reading a password protected excel 2007 file with OpenXml.

Turns out that the API Gateway was encoding it as base64, it needed to be passed in as binary and not encoded. One thing I forgot to do was also deploy it API Gateway.

Related

Azure Function App Could not load System.IO.Pipelines connecting to Redis

Created a new Function App, HTTP trigger in VS2019 (16.8.3) to connect to Azure Cache for Redis. Added StackExchange.Redis 2.2.4 from nuget.
local.settings.json contains the key/value of RedisConnectionFromKeyVault and the Primary Connection String from Access keys from the portal.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"RedisConnectionFromKeyVault": "<<SNIP>>.redis.cache.windows.net:6380,password=<<SNIP>>,ssl=True,abortConnect=False"
}
}
Added the following lines to the default function code:
var connectionRedis = Environment.GetEnvironmentVariable("RedisConnectionFromKeyVault", EnvironmentVariableTarget.Process);
var cache = ConnectionMultiplexer.Connect(connectionRedis).GetDatabase();
When I run and trigger the function app locally I get the following exception on the ConnectionMultiplexer.Connect call.
System.Private.CoreLib: Exception while executing function: Function1. StackExchange.Redis: Could not load file or assembly 'System.IO.Pipelines, Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
at StackExchange.Redis.ConnectionMultiplexer.Connect(ConfigurationOptions configuration, TextWriter log) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 1032
at StackExchange.Redis.ConnectionMultiplexer.Connect(String configuration, TextWriter log) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 1015
at FunctionApp1.Function1.<Run>d__0.MoveNext() in E:\GitRepos\FunctionApp1\FunctionApp1\Function1.cs:line 26
Tried similar code in a console app and it works fine?
What am I missing? Why does the function app think it cannot find the System.IO.Pipelines assembly?
Even if I include the System.IO.Piplelines nuget package explicitly it does not find it?
Looks like this is a known issue with Azure Functions as noted at https://github.com/Azure/azure-functions-host/issues/5894
Issues were raised with StackExchange.Redis
https://github.com/StackExchange/StackExchange.Redis/issues/1637
https://github.com/StackExchange/StackExchange.Redis/issues/1655
Issue can be resolved by adding the _FunctionsSkipCleanOutput element as below to the csproj
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput> <!-- *** this line is new ** -->
</PropertyGroup>
OK I found how to workaround this.
I was referring to the package StackExchange.Redis 2.2.4 (which was making Azure wanting to load System.IO.Pipelines 5.x).
I replaced that package with Microsoft.Extensions.Caching.StackExchangeRedis 5.0.1 (which in turn references StackExchange.Redis 2.0.593 which references System.IO.Pipeline 4.5.2).
Now my functions are working correctly.
Not sure if this is a long term solution though.
Thanks.

Xamarin Android share PDF. Permission denied for the attachment [duplicate]

My app creates mails with attachments, and uses an intent with Intent.ACTION_SEND to launch a mail app.
It works with all the mail apps I tested with, except for the new Gmail 5.0 (it works with Gmail 4.9), where the mail opens without attachment, showing the error: "Permission denied for the attachment".
There are no useful messages from Gmail on logcat. I only tested Gmail 5.0 on Android KitKat, but on multiple devices.
I create the file for the attachment like this:
String fileName = "file-name_something_like_this";
FileOutputStream output = context.openFileOutput(
fileName, Context.MODE_WORLD_READABLE);
// Write data to output...
output.close();
File fileToSend = new File(context.getFilesDir(), fileName);
I'm aware of the security concerns with MODE_WORLD_READABLE.
I send the intent like this:
public static void compose(
Context context,
String address,
String subject,
String body,
File attachment) {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("message/rfc822");
emailIntent.putExtra(
Intent.EXTRA_EMAIL, new String[] { address });
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_TEXT, body);
emailIntent.putExtra(
Intent.EXTRA_STREAM,
Uri.fromFile(attachment));
Intent chooser = Intent.createChooser(
emailIntent,
context.getString(R.string.send_mail_chooser));
context.startActivity(chooser);
}
Is there anything I do wrong when creating the file or sending the intent? Is there a better way to start a mail app with attachment? Alternatively - has someone encountered this problem and found a workaround for it?
Thanks!
I was able to pass a screenshot .jpeg file from my app to GMail 5.0 through an Intent. The key was in this answer.
Everything I have from #natasky 's code is nearly identical but instead, I have the file's directory as
context.getExternalCacheDir();
Which "represents the external storage directory where you should save cache files" (documentation)
GMail 5.0 added some security checks to attachments it receives from an Intent. These are unrelated to unix permissions, so the fact that the file is readable doesn't matter.
When the attachment Uri is a file://, it'll only accept files from external storage, the private directory of gmail itself, or world-readable files from the private data directory of the calling app.
The problem with this security check is that it relies on gmail being able to find the caller app, which is only reliable when the caller has asked for result. In your code above, you do not ask for result and therefore gmail does not know who the caller is, and rejects your file.
Since it worked for you in 4.9 but not in 5.0, you know it's not a unix permission problem, so the reason must be the new checks.
TL;DR answer:
replace startActivity with startActivityForResult.
Or better yet, use a content provider.
Use getExternalCacheDir() with File.createTempFile.
Use the following to create a temporary file in the external cache directory:
File tempFile = File.createTempFile("fileName", ".txt", context.getExternalCacheDir());
Then copy your original file's content to tempFile,
FileWriter fw = new FileWriter(tempFile);
FileReader fr = new FileReader(Data.ERR_BAK_FILE);
int c = fr.read();
while (c != -1) {
fw.write(c);
c = fr.read();
}
fr.close();
fw.flush();
fw.close();
now put your file to intent,
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
You should implement a FileProvider, which can create Uris for your app's internal files. Other apps are granted permission to read these Uris. Then, simply instead of calling Uri.fromFile(attachment), you instantiate your FileProvider and use:
fileProvider.getUriForFile(attachment);
Google have an answer for that issue:
Store the data in your own ContentProvider, making sure that other apps have the correct permission to access your provider. The preferred mechanism for providing access is to use per-URI permissions which are temporary and only grant access to the receiving application. An easy way to create a ContentProvider like this is to use the FileProvider helper class.
Use the system MediaStore. The MediaStore is primarily aimed at video, audio and image MIME types, however beginning with Android 3.0 (API level 11) it can also store non-media types (see MediaStore.Files for more info). Files can be inserted into the MediaStore using scanFile() after which a content:// style Uri suitable for sharing is passed to the provided onScanCompleted() callback. Note that once added to the system MediaStore the content is accessible to any app on the device.
Also you can try set permissions for your file:
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
And finally you can copy/store your files in external storage - permissions not needed there.
I tested it and I found out that it was definitely private storage access problem.
When you attach some file to Gmail (over 5.0) do not use the file from private storage such as /data/data/package/. Try to use /storage/sdcard.
You can successfully attach your file.
Not sure why GMail 5.0 doesn't like certain file paths (which I've confirmed it does have read access to), but an apparently better solution is to implement your own ContentProvider class to serve the file. It's actually somewhat simple, and I found a decent example here: http://stephendnicholas.com/archives/974
Be sure to add the tag to your app manifest, and include a "android:grantUriPermissions="true"" within that. You'll also want to implement getType() and return the appropriate MIME type for the file URI, otherwise some apps wont work with this... There's an example of that in the comment section on the link.
I was having this problem and finally found an easy way to send email with attachment. Here is the code
public void SendEmail(){
try {
//saving image
String randomNameOfPic = Calendar.DAY_OF_YEAR+DateFormat.getTimeInstance().toString();
File file = new File(ActivityRecharge.this.getCacheDir(), "slip"+ randomNameOfPic+ ".jpg");
FileOutputStream fOut = new FileOutputStream(file);
myPic.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.flush();
fOut.close();
file.setReadable(true, false);
//sending email
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"zohabali5#gmail.com"});
intent.putExtra(Intent.EXTRA_SUBJECT, "Recharge Account");
intent.putExtra(Intent.EXTRA_TEXT, "body text");
//Uri uri = Uri.parse("file://" + fileAbsolutePath);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(Intent.createChooser(intent, "Send email..."),12);
}catch (Exception e){
Toast.makeText(ActivityRecharge.this,"Unable to open Email intent",Toast.LENGTH_LONG).show();
}
}
In this code "myPic" is bitmap which was returned by camera intent
Step 1: Add authority in your attached URI
Uri uri = FileProvider.getUriForFile(context, ""com.yourpackage", file);
Same as your manifest file provide name
android:authorities="com.yourpackage"
Step 2`; Add flag for allow to read
myIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Connect to Oracle from Azure Web Role - empty error message

I't trying to port an existing web application to run as an Azure Web Role. This application uses Oracle DB, which I've installed on an Azure VM using one of the new Images available there.
The problem arises when I try to connect from the web application to the database. I'm able to connect to the database from my developer PC (from Visual Studio using ODBC) and I'm able to telnet to the port, so no firewall issues.
I'm using this technique: http://www.splinter.com.au/using-the-new-odpnet-to-access-oracle-from-c/ which has been described several places online, including here on StackOverflow. The only difference is that I use Oracle 12 instead of 11, and use the appropriate 64 bit libraries.
The error I get, is not very descriptive:
[OracleException (0x80004005)]
Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck, Int32 isRecoverable) +1199
Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, Object src) +53
Oracle.DataAccess.Client.OracleConnection.Open() +4555
NHibernate.Connection.DriverConnectionProvider.GetConnection() +378
NHibernate.Tool.hbm2ddl.SuppliedConnectionProviderConnectionHelper.Prepare() +92
NHibernate.Tool.hbm2ddl.SchemaMetadataUpdater.GetReservedWords(Dialect dialect, IConnectionHelper connectionHelper) +154
NHibernate.Tool.hbm2ddl.SchemaMetadataUpdater.Update(ISessionFactory sessionFactory) +312
NHibernate.Impl.SessionFactoryImpl..ctor(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners) +1934
NHibernate.Cfg.Configuration.BuildSessionFactory() +292
FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() +54
[FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
]
FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() +111
MAP.NHibernateHelper.CreateSessionFactory() in C:\ProjectSVN\FluentWims\DataAccessLayer\DataMapping\NHibernateHelper.vb:102
MAP.NHibernateHelper.get_SessionFactory() in C:\ProjectSVN\FluentWims\DataAccessLayer\DataMapping\NHibernateHelper.vb:16
(Some lines deleted at the end as it contains some details I don't want to share publicly and I'm pretty sure they are irrelevant)
I've decompiled the managed code (OracleDataAccess.dll) and traced the problem to a call to this wrapped native call:
<DllImport("OraOps12.dll", EntryPoint:="OpsConOpen", CallingConvention:=CallingConvention.Cdecl, CharSet:=CharSet.Unicode)> _
Public Shared Function Open(ByRef opsConCtx As IntPtr, ByRef opsErrCtx As IntPtr, ByRef pOpoConValCtx As OpoConValCtx, ByRef pOpoConRefCtx As OpoConRefCtx) As Integer
End Function
This returns -1, which isn't recognized as a known error code, and thus creates this exception which means next to nothing (at least not to me, even after googling like crazy ;)).
I have checked that if I remove OraOps12.dll, I get a different error message, and I've seen in ProcMon that the file is in fact found where I put it. I can find next to nothing about OraOps online, and what it means that this method returns -1.
Does anyone know what might be going on here, and what might be wrong?
UPDATE
I've tried to look with a network monitor, at what is being sent to the oracle database, and I can't find any traffic - so OraOps seems to be called, but it doesn't get as far as to try to communicate with the database server.
The connection string I'm using, is copy/paste from the working connection in Visual Studio, so I assume it is correct. Even if it wasn't, I would expect a more descriptive error message back...

MVC Null exception after deploying to web server

I have an MVC 3 application that works fine when running locally from visual studio,
There are two bat files that pre compile the application ready for deployment, when i run the bat files and upload the deployment folder to the web server a load of errors are thrown including a null exception error,
The error can be seen by visiting the following URL, i can also provide the full stack trace on a document if required, i didnt want to post it here as its so big.
error can be seen here
I cant understand where the error is coming from as everything works locally, t seems these errors are being created when the bat files are compiling the application, has anyone had similar experiences after deploying an MVC app? can anyone offer any advice on what may be causing the problem?
Thanks
Liam
UPDATE=============
This is the GetTax method, this code has been thoroughly tested as its part of NopCommerce 2.2, the errors only occur after the solution is compiled via the BAT files which is again standard for building a nop commerce 2.2 app, am i right in thinking its got to be something on my machine that is causing these problems when the BAT files are ran and the code is compiled for deployment?
public virtual decimal GetTaxRate(ProductVariant productVariant, int taxCategoryId,
Customer customer)
{
//tax exempt
if (IsTaxExempt(productVariant, customer))
{
return decimal.Zero;
}
//tax request
var calculateTaxRequest = CreateCalculateTaxRequest(productVariant, taxCategoryId, customer);
//make EU VAT exempt validation (the European Union Value Added Tax)
if (_taxSettings.EuVatEnabled)
{
if (IsVatExempt(calculateTaxRequest.Address, calculateTaxRequest.Customer))
{
//return zero if VAT is not chargeable
return decimal.Zero;
}
}
//active tax provider
var activeTaxProvider = LoadActiveTaxProvider();
//get tax rate
var calculateTaxResult = activeTaxProvider.GetTaxRate(calculateTaxRequest);
if (calculateTaxResult.Success)
return calculateTaxResult.TaxRate;
else
return decimal.Zero;
}
The stack trace indicates that it's coming from the method GetTaxRate in TaxService.cs. I'm guessing this isn't anything ASP.NET MVC specific, but a deployment issue. It could be database permissions or connection strings.. you'll have to check what that method is doing.
Nop.Services.Tax.TaxService.GetTaxRate(ProductVariant productVariant, Int32 taxCategoryId, Customer customer) in c:\Nop 2.2 Source\just4fashion2.2source\Libraries\Nop.Services\Tax\TaxService.cs:240
It probably has something do with a configuration mismatch between your development and production environment.
If you look at the top of the stack trace you see that is has probably nothing to do with MVC but with someting in your TaxService.
[NullReferenceException: Object reference not set to an instance of an object.]
Nop.Services.Tax.TaxService.GetTaxRate(ProductVariant productVariant, Int32 taxCategoryId, Customer customer) in c:\Nop 2.2 Source\just4fashion2.2source\Libraries\Nop.Services\Tax\TaxService.cs:240
You need to check on which element the Null exception occurs.
Things to check:
Is productVariant null?
Is customer null?
Are there any other elements accessed in this function like a Repository or Factory that could be null?
Are there any configuration changes between local and production like connectionstring, logging or security settings?

Properly Establishing an ApplicationEndpoint in UCMA 3.0

I've been struggling with getting an application endpoint working on UCMA 3.0. I am trying to run an application on a server separate from the Lync server which uses a registered ApplicationEndpoint to monitor presence and act as a bot which can send other users messages. I used to have my code working with a UserEndpoint (which was fine for monitoring presence), but did not have the capabilities to send IMs to other Lync users.
After searching the web, I'm finally at the point where I'm getting this error when running my code:
System.ArgumentException was unhandled
Message=An ApplicationEndpoint can be registered only if proxy and Multual Tls have been specified.
Source=Microsoft.Rtc.Collaboration
StackTrace:
at Microsoft.Rtc.Collaboration.ApplicationEndpoint..ctor(CollaborationPlatform platform, ApplicationEndpointSettings settings)
at Waldo.endpointHelper.CreateApplicationEndpoint(ApplicationEndpointSettings applicationEndpointSettings) in C:\Users\l1m5\Desktop\waldoproject\trunk\WaldoSoln\waldoGrabPresence\endpointHelper.cs:line 117
at Waldo.endpointHelper.CreateEstablishedApplicationEndpoint(String endpointFriendlyName) in C:\Users\l1m5\Desktop\waldoproject\trunk\WaldoSoln\waldoGrabPresence\endpointHelper.cs:line 228
at Waldo.waldoGrabPresence.Run() in C:\Users\l1m5\Desktop\waldoproject\trunk\WaldoSoln\waldoGrabPresence\waldoGrabPresence.cs:line 60
at Waldo.waldoGrabPresence.Main(String[] args) in C:\Users\l1m5\Desktop\waldoproject\trunk\WaldoSoln\waldoGrabPresence\waldoGrabPresence.cs:line 42
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
After some searching, I followed the instructions here: http://blogs.claritycon.com/blogs/michael_greenlee/archive/2009/03/21/installing-a-certificate-for-ucma-v2-0-applications.aspx to import a certificate onto the server that I'm trying to run the application on, but to no avail.
So at this point, I think that there must be something wrong with how I'm setting up the ApplicationEndpointSettings, CollaberationPlatform or ApplicationEndpoint objects. Here's how I'm doing it:
ApplicationEndpointSettings settings = new ApplicationEndpointSettings(_ownerURIPrompt, _serverFQDNPrompt, _trustedPortPrompt);
ServerPlatformSettings settings = new ServerPlatformSettings(null, _serverFQDNPrompt, _trustedPortPrompt, _trustedApplicationGRUU);
_collabPlatform = new CollaborationPlatform(settings);
_applicationEndpoint = new ApplicationEndpoint(_collabPlatform, applicationEndpointSettings);
Does anyone see any problems with what I'm doing? Or, better yet, does anyone know of a blog that walks you through establishing an application endpoint in the situation I'm in? I work really well with tutorials or samples, but have not found one that seems to accomplish what I'm trying to do.
Thanks for the help!
The procedure to get a certificate in Lync is very different than OCS2007, and much easier. The link you posted is for UCMA2, and OCS, I believe. In Lync, it's basically two powershell statements.
1) Request-CSCertificate -Action new -Type default -CA -Verbose
2) Save the results of that statement, take the thumbprint, use it as the parameter to:
Set-CsCertificate -Type Default -Thumbprint XXXXXXXXXXXXXXXXXXXX
Installing UCMA 3.0 and Creating a Lync Server 2010 Trusted Application Pool
use powershell to provision a trusted application endpoint. The command to explore is new-trustedapplicationendpoint. The error you are getting is due to no trusted endpoint being registered, even though you may have your trusted application registered, it needs an endpoint to work and that endpoint must be first registered before you provision the platform.
The SDK CHM file should be your friend here! This section is about app activation and provisioning
Pass the certificate to the ServerPlatformSettings object, then it works. I had the similar problem, and the problem is resolved after using the ServerPlatformSettings(string applicationUserAgent, string localhost, int port, string gruu, string certificateIssuerName, byte[] certificateSerialNumber) constructor for the ServerPlatformSettings.

Resources