A few days ago we updated 2sxc from version 9.33.0 to 11.7.3. And when running ToSic.SexyContent.Environment.Dnn7.Factory.App(appId, portalSettings), in the scheduled tasks of a custom dnn module, it gives the following error.
EXCEPTIONSystem.NullReferenceException: Object reference not set to an instance of an object. at ToSic.SexyContent.Environment.DnnEnvironment.get_DefaultLanguage() in C:\Projects\2sxc-dnn742\Website\DesktopModules\ToSIC_SexyContent\2sxc Dnn\Environment\DnnEnvironment.cs:line 28 at ToSic.Eav.Persistence.Efc.Efc11Loader.LoadEntities(AppDataPackage app, Int32[] entityIds) at ToSic.Eav.Persistence.Efc.Efc11Loader.<>c__DisplayClass5_0.b__0() at ToSic.Eav.App.AppDataPackage.Load(Log parentLog, Action loader) in C:\Projects\eav-server\ToSic.Eav.Core\App\AppDataPackage.cs:line 181 at ToSic.Eav.Persistence.Efc.Efc11Loader.Update(AppDataPackage app, AppPackageLoadingSteps startAt, Int32[] entityIds, Log parentLog) at ToSic.Eav.Persistence.Efc.Efc11Loader.AppPackage(Int32 appId, Int32[] entityIds, Log parentLog) at ToSic.Eav.DataSources.Caches.BaseCache.EnsureCache() in C:\Projects\eav-server\ToSic.Eav.DataSources\Caches\BaseCache.cs:line 96 at ToSic.Eav.Apps.App..ctor(Int32 zoneId, Int32 appId, Boolean allowSideEffects, Func`2 buildConfiguration, Log parentLog, String logMsg) at ToSic.Eav.Apps.App..ctor(IAppEnvironment env, ITenant tenant, Int32 zoneId, Int32 appId, Boolean allowSideEffects, Func`2 buildConfiguration, Log parentLog) at ToSic.SexyContent.Environment.Dnn7.Factory.App(Int32 appId, PortalSettings ownerPortalSettings, Boolean versioningEnabled, Boolean showDrafts) in C:\Projects\2sxc-dnn742\Website\DesktopModules\ToSIC_SexyContent\2sxc Dnn\Environment\Dnn7\Factory.cs:line 55
We have detected a very similar error when updating from version 9.33.0 to 9.35.
Environment:
DNN: 09.07.01 2sxc: 11.7.3.
Target Framework custom dnn module: .NET Framework 4.7.2
As #iJungleBoy says, when a scheduled task is executed the system doesn't have a current PortalSettings. I understand that SxcApiController needs a DNN context and at the same time it inherits from DnnApiController. The only way to ensure that a DNN context exists is to publish an endpoint and make a request from the scheduled task.
This is because when you call an endpoint from a controller that inherits from DnnApiController, DNN uses the request to create a context and a current PortalSettings.
You can do something like this from your scheduled task:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("YOUR_CONTROLLER_ENDPOINT");
request.Method = "GET";
request.ContentType = "application/json; charset=utf-8";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream streamResponse = response.GetResponseStream();
// Deserialize response
var myEndpointResponse = JsonConvert.DeserializeObject<MyResponseObject>(new StreamReader(streamResponse).ReadToEnd());
welcome to StackOverflow :)
The error you posted is almost unreadable (all on one line), so it's hard to figure out anything.
My guess is that since you're running in a schedule task, the system doesn't have a current PortalSettings, which is usually needed for things like getting the current language. These errors sometimes happen after bigger 2sxc changes and then usually pop up in the search (which is a scheduled task). But your case may be a bit more complex, so I don't know.
Without knowing the specifics, it's hard to give a tip, but it could be a bug in 2sxc not handling a fallback in this situation. I suggest you try to figure it out more in detail or get someone to help you on your site.
Thank you for your response.
I have been debugging 2sxc source code and it seems that the issue appears when you run the following in Factory.cs
var appStuff = app.Init(new AppIdentity(zoneId, appId),
ConfigurationProvider.Build(showDrafts, publishingEnabled, new LookUpEngine(parentLog)),
true, parentLog);
That generates the error in DnnTenant.cs in the following line.
public override string DefaultLanguage => _defaultLanguage ?? (_defaultLanguage = UnwrappedContents.DefaultLanguage.ToLowerInvariant());
The error message is as follows:
EXCEPTIONSystem.NullReferenceException: Object reference not set to an
instance of an object. at
ToSic.SexyContent.Environment.DnnEnvironment.get_DefaultLanguage() in
C:\Projects\2sxc-dnn742\Website\DesktopModules\ToSIC_SexyContent\2sxc
Dnn\Environment\DnnEnvironment.cs:line 28
I emphasize that the error seems to be solved after some time, but it reappears when the cache is cleaned and Dnn is restarted.
I suspect it has to do with the UnwrappedContents variable.
I have not found in the source code the way to debug the Eav.Factory.Resolve<App>() method. Where is the code of the Eav.Factory.Resolve<App>() method?
Related
I have a web-application built in ASP.NET Webforms VB.NET. I am creating a method for exporting the pages via urls utilising the WKHTMLTOPDF and NReco PDF Generator libraries.
During my local development, everything seems to work ok, other than the odd "Process is already in use" when i have rebooted my PC and not even performed anything prior.
When I have uploaded the site to our server, the PDF library seems to never work and I am faced with a not so obvious error. When I attempt to export any page to anything, or even text to a pdf, I get this within our logs:
Inner Exception Type: NReco.PdfGenerator.WkHtmlToPdfException
Inner Exception: Exit with code 1, due to unknown error. (exit code: 1)
Inner Source: NReco.PdfGenerator
Inner Stack Trace:
at NReco.PdfGenerator.HtmlToPdfConverter.CheckExitCode(Int32 exitCode, String lastErrLine, Boolean outputNotEmpty)
at NReco.PdfGenerator.HtmlToPdfConverter.InvokeWkHtmlToPdf(PdfSettings pdfSettings, String inputContent, Stream outputStream)
at NReco.PdfGenerator.HtmlToPdfConverter.GeneratePdfInternal(WkHtmlInput[] htmlFiles, String inputContent, String coverHtml, String outputPdfFilePath, Stream outputStream)
Exception Type: System.Exception
Exception: Cannot generate PDF: Exit with code 1, due to unknown error. (exit code: 1)
Source: Exporting
Stack Trace:
at NReco.PdfGenerator.HtmlToPdfConverter.GeneratePdfInternal(WkHtmlInput[] htmlFiles, String inputContent, String coverHtml, String outputPdfFilePath, Stream outputStream)
at NReco.PdfGenerator.HtmlToPdfConverter.GeneratePdf(String htmlContent, String coverHtml, String outputPdfFilePath)
at PROJECT.Export.DownloadFiles(List`1 list) in C:\Users\NAME\source\repos\PROJECT\Export.aspx.vb:line 252.
I have ensured the project contains all the relevant files, I have even installed WKHTMLTOPDF on both server and development machine. Utilising the CMD I can generate ANY PDF but within my application, it seems to always fail on our live production server.
My code for generating the PDF is quite simplistic:
If check = True Then
Try
'Generate PDF
'htmlToPdf.GeneratePdfFromFile(exp.URL, Nothing, "..\" & pathURL)
htmlToPdf.GeneratePdf("<h3> TEST PDF </h3> ", Nothing, "..\" & pathURL)
'Set download
download = True
'Catch exception, log it
Catch ex As Exception
ExceptionUtility.LogException(ex, "Exporting")
End Try
End If
Can anyone offer any insight as to how I can overcome this? I spent all day yesterday searching through forums and not coming to a solution!
Any help is highly appreciated.
Exit code 1 means that wkhtmltopdf was unable to render your HTML input for some reason.
To get more details (full wkhtmltopdf's console log output) you may handle LogReceived event.
PdfGenerator executes wkhtmltopdf with System.Diagnostics.Process API, so it should work exactly like if you run it (on the same server) in the command line. Differences may occur if this is ASP.NET app hosted in IIS, and in some cases app pool may be configured to use rather restrictive credentials.
There is a plethora of frustratingly incorrect (better description - "close but no cigar") information concerning remote access to JBoss EJBs from a standalone application. I've been beating my head against this wall for over a day with no success.
I'm trying to port an EJB from WebLogic to JBoss, which is called by a standalone application running on another server.
I've been here, here, and several other places chasing down various "solutions" to my problem without success. I've tried reading the official documentation which wants me to install a "quickstart" based on Maven, which may or may not fit my situation, and which so far I have decided not to pursue. (My project is not built with Maven, it uses Gradle, but I am reasonably certain that I've managed to get all the right dependencies deployed).
I have a stateful EJB deployed in a WAR inside an EAR (previous implementation of deploying it simply in a WAR did not help matters).
I configure the client thusly:
public InitialContext createInitialContext() throws NamingException {
Properties prop = new Properties();
prop.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
prop.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jboss.naming.remote.client.InitialContextFactory");
prop.put(Context.PROVIDER_URL, purl);
prop.put(Context.SECURITY_PRINCIPAL, "myusername");
prop.put(Context.SECURITY_CREDENTIALS, "mypassword");
prop.put("jboss.naming.client.ejb.context", false);
return new InitialContext(prop);
}
public void closeContext(Context context) throws NamingException {
if (context != null) {
context.close();
}
}
private String getJndiName(
String prefix,
String appName,
String moduleName,
String distinctName,
String beanName,
Class viewClass,
boolean stateful)
{
StringBuilder builder = new StringBuilder();
if (prefix != null && prefix.length() > 0) {
builder.append(prefix).append(':');
}
builder.append(appName)
.append('/')
.append(moduleName)
.append('/')
.append(distinctName)
.append('/')
.append(beanName).append('!')
.append(viewClass.getName());
if (stateful) {
builder.append("?stateful");
}
return builder.toString();
}
public Object lookup(Context context) throws NamingException {
final String prefix = "ejb";
final String appName = "myearname";
final String moduleName = "mywarname";
final String distinctName = "";
final String beanName = "MyBean";
final Class viewClass = MyBeanInterface.class;
String jndi = getJndiName(prefix, appName, moduleName, distinctName, beanName, viewClass, true);
return context.lookup(jndi);
}
Note that no "distinct name" is provided as none is needed. "distinct name" is supposed to be optional:
All of this gets invoked by:
MyBeanInterface sstatus = null;
try {
ctx = createInitialContext();
sstatus = (MyBeanInterface) lookup(ctx);
} catch (Exception ex) {
...
}
When this code is invoked, the following error message is produced:
Caused by: java.lang.IllegalStateException: EJBCLIENT000024: No EJB receiver available for handling [appName:SockTransport, moduleName:SockTransport, distinctName:] combination
at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:873) ~[ttjd.jar:?]
at org.jboss.ejb.client.EJBClient.createSessionWithPossibleRetries(EJBClient.java:222) ~[ttjd.jar:?]
at org.jboss.ejb.client.EJBClient.createSession(EJBClient.java:202) ~[ttjd.jar:?]
at org.jboss.ejb.client.naming.ejb.EjbNamingContext.doCreateProxy(EjbNamingContext.java:227) ~[ttjd.jar:?]
at org.jboss.ejb.client.naming.ejb.EjbNamingContext.createEjbProxy(EjbNamingContext.java:204) ~[ttjd.jar:?]
Using the above code, the JNDI name I am supplying is
ejb:myearname/mywarname//MyBean!com.whatever.my.package.MyBeanInterface. Note the double slash caused by the missing distinctName. I can and have rejiggered this code to produce instead ejb:myearname/mywarname/MyBean!com.whatever.my.package.MyBeanInterface and this makes no difference.
Frankly, I think this error message is a red herring. I suspect that there is some other problem with my setup that is not being caught and breaking on this interface. I don't think the distinct name or lack thereof has anything to do with the problem. I think that's simply how they log the object that can't be looked up.
Before I go down the path of figuring out how to add a useless "distinct name" in a probably vain attempt to keep JBOSS happy, can someone venture a guess as to what the real problem may be?
UPDATE:
The suggestions of #Steve_C are quite illuminating but I still have not gotten them to work. He left a few points out of the initial context creation:
Context.URL_PKG_PREFIXES
Context.INITIAL_CONTEXT_FACTORY
"jboss.naming.client.ejb.context"
but these were mentioned in the resource he cited - very handy by the way.
So I added these and my createInitialContext method now looks like this:
public InitialContext createInitialContext() throws NamingException {
Properties prop = new Properties();
prop.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
prop.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jboss.naming.remote.client.InitialContextFactory");
prop.put(Context.PROVIDER_URL, "http-remoting://{server-ip}:{server-port});
prop.put("jboss.naming.client.ejb.context", true);
return new InitialContext(prop);
}
Why PROVIDER_URL is necessary when I've already supplied server-ip and server-port in the jboss-ejb-client.properties file remains mysterious, but it makes a difference.
With these three items added to my initial context environment, now I get a different error message (EJBCLIENT000025 instead of EJBCLIENT000024):
java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling [appName:SockTransport, moduleName:SockTransport, distinctName:] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext#67f639d3
at org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:798) ~[ttjd.jar:?]
at org.jboss.ejb.client.ReceiverInterceptor.handleInvocation(ReceiverInterceptor.java:128) ~[ttjd.jar:?]
at org.jboss.ejb.client.EJBClientInvocationContext.sendRequest(EJBClientInvocationContext.java:186) ~[ttjd.jar:?]
at org.jboss.ejb.client.EJBInvocationHandler.sendRequestWithPossibleRetries(EJBInvocationHandler.java:255) ~[ttjd.jar:?]
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:200) ~[ttjd.jar:?]
at org.jboss.ejb.client.EJBInvocationHandler.doInvoke(EJBInvocationHandler.java:183) ~[ttjd.jar:?]
at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:146) ~[ttjd.jar:?]
at com.sun.proxy.$Proxy20.create(Unknown Source) ~[?:?]
I suppose this counts as progress, but I'm finding this more difficult than it needs to be. I wonder if these new properties need to be in the properties file, but the official documentation pretty clearly says they don't.
The most flexible WildFly/JBossEAP remote EJB lookup and invocation can be done as follows:
Create a jboss-ejb-client.properties file which must be on the client classpath:
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=<ip of jboss eap host>
remote.connection.default.port = 8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
The EJBCLIENT000024: No EJB receiver available for handling error message is a symptom of a missing jboss-ejb-client.properties file.
Create an InitialContext:
Properties jndiProps = new Properties();
jndiProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
Context ctx = new InitialContext(jndiProps);
Note that no other properties are required.
Lookup the bean and call it:
ServiceLogic beanRemoteInterface = (ServiceLogic) ctx.lookup("ejb:/WhizBangSessionEJB/WhizBangSessionEJB!com.whatever.hostinterface.ServiceLogic?stateful");
String bar = beanRemoteInterface.sayHello();
System.out.println("Remote Foo bean returned " + bar);
Note the ?stateful on the end of the JNDI name that is required for stateful EJBs.
Output:
Jan 11, 2017 11:07:46 PM org.jboss.ejb.client.EJBClient <clinit>
INFO: JBoss EJB Client version 2.1.4.Final
Jan 11, 2017 11:07:46 PM org.xnio.Xnio <clinit>
INFO: XNIO version 3.4.0.Final
Jan 11, 2017 11:07:46 PM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.4.0.Final
Jan 11, 2017 11:07:46 PM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 4.0.21.Final
Jan 11, 2017 11:07:46 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
Jan 11, 2017 11:07:46 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext#29ca901e, receiver=Remoting connection EJB receiver [connection=org.jboss.ejb.client.remoting.ConnectionPool$PooledConnection#5649fd9b,channel=jboss.ejb,nodename=steves-mbp]} on channel Channel ID ecac0ca6 (outbound) of Remoting connection 6536e911 to /192.168.12.6:8080 of endpoint "config-based-ejb-client-endpoint" <520a3426>
Remote Foo bean returned hello
More information can be found in Remote EJB invocations via JNDI - EJB client API or remote-naming project.
More sample code can be found in the QuickStart repo at wildfly/quickstart/ejb-remote
PS. If you really want to set the distinct-name then you need to add a jboss-ejb3.xml file to your EJB jar containing:
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd"
version="3.1"
impl-version="2.0">
<distinct-name>something-distinct</distinct-name>
</jboss:ejb-jar>
Dynamic EJB Client Properties
If you need to be able to provision the jboss-ejb-client.properties
dynamically then the simplest solution would be generate this file
on the fly, possibly at client initialisation time.
Set the jboss.ejb.client.properties.file.path system property to
point at a secure writable file system location. An insecure example might be something like
-Djboss.ejb.client.properties.file.path=/tmp/whizbang-ejb.properties
or
System.setProperty("jboss.ejb.client.properties.file.path", "/tmp/whizbang-ejb.properties");
Generate a properties file named
with the String defined by jboss.ejb.client.properties.file.path according to the format described for jboss-ejb-client.properties files.
Proceed with InitialContext creation
There are other alternatives that involve hacking the provided jboss-ejb-client
code. However you need to remember that this is LGPL code and you and your company
would need to make your hacks publicly available.
Before sharing what I learned I want to give a big shout-out to #Steve_C who went way beyond the call of duty in helping me, including a lengthy chat session. In case anyone wonders, he is not ME, by the way.
Meaning no disrespect to #Steve_C or his answer (which I have upvoted as useful), there is more to be said here, as I've learned from very painful experience.
Here are some things I have learned:
1) It is necessary to have a jboss-ejb-client.properties file.
2) This file can be located either on the classpath or specified in a location specified by the following System property, which I set just prior to invoking the InitialContext constructor:
System.setProperty("jboss.ejb.client.properties.file.path", "/path/to/properties/file");
return new InitialContext(prop);
3) This file must name the connections:
remote.connections=conn1,conn2
4) For each connection named in the above property, host and port entries must be stored in the properties file
remote.connection.conn1.host=10.0.0.1
remote.connection.conn1.port=8080
remote.connection.conn2.host=10.0.0.2
remote.connection.conn2.port=8080
5) For each connection named, there must also be some method of authentication specified, either
a)
remote.connection.conn1.username=user1
remote.connection.conn1.password=topSecret
remote.connection.conn2.username=user2
remote.connection.conn2.password=open_sesame
or b)
remote.connection.conn1.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.conn2.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
which literally indicates that anonymous no-password invocations are not disallowed. (Let's hear it for double negatives!) I suppose it would be theoretically possible to have one connection using a password and another allowing anonymous login but I can't imagine why. However this is done, it must be specified connection by connection. There is an incorrect example on the web that includes both
remote.connection.conn2.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
and username/password properties for the connection. The net effect of this is that the credentials can be incorrect and you still get login. I tried this and found it to be the case.
6) In spite of appearances, the specifying of java.naming.provider.url is necessary. It would be nice if JBoss could figure this out from the connection host and port properties mentioned above, but it can't! There may or may not be a good reason for this, I simply do not know.
Annoyingly, this CANNOT be specified in the Properties file. This seems to be a bug in the JBoss client. Since ":" is equivalent to "=" in the Java properties file specification, it is impossible to store URLs there with the http-remote:// notation or any url with the colon slash slash. The colon must be escaped with a backslash but evidently the JBoss client code is not calling Properties.load() to resolve the escaping correctly, but rather attempting to read it line for line? So this one must be specified in the Properties passed to the InitialContext creation. I have tried both ways and found that specify it in code works, whereas specifying it in a properties file doesn't.
So we have the unfortunate situation that there are two methods of supplying data to the InitialContext, some by properties file and some in the initial environment Hashtable passed to the InitialContext constructor. Some things must be done in one place, and other things must be done in the other. And none of this is properly documented.
We're using plupload for users to upload files to our VPS.
Here is the plupload code:
var uploader = new plupload.Uploader({
browse_button: 'fileSelectorLink',
container: 'uploadContainer',
drop_element: 'uploadbox',
url: '/UploadHandler.ashx',
unique_names: true,
multi_selection: false,
flash_swf_url: '/scripts/plupload/js/Moxie.swf',
silverlight_xap_url: '/scripts/plupload/js/Moxie.xap'
});
He is the code for processing the request:
Public Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim runtime As String = If(context.Request("runtime") IsNot Nothing, context.Request("runtime"), "Unknown")
If context.Request IsNot Nothing Then
If context.Request.Files.Count > 0 Then
Dim fileUpload As HttpPostedFile = context.Request.Files(0)
...
Else
' Throw an exception
End If
End Sub
Occasionally (about 2% of the time) the exception will get thrown. Here is an example of request that threw an error:
Runtime: html5
Request.ContentType: multipart/form-data; boundary=----WebKitFormBoundaryo7JAtlhKsg8xDcQT
Request.ContentLength: 3758089
Request.ContentEncoding: System.Text.SBCSCodePageEncoding
Request.TotalBytes: 3179067
The errors seem to happen across different browsers and OSs (even modern browsers), so that doesn't seem to be the issue. Plupload should fall back to other versions if browser doesn't handle async file uploads. I thought the ContentEncoding seemed odd, but it seems to always say that (maybe plupload works like that?). The only thing that jumped out at me is that the ContentLength and TotalBytes were different, but in my local testing they were the same. Could that be a problem?
Been stuck on this issue for a few days and haven't had any good leads.
The failures could be occurring when users abort the upload (usually indicated by "The remote host closed the connection." exceptions), are encountering network latency, perhaps from HTTP timeouts, maybe even an issue with the Plupload code. My apologies for not being specific with the reason, however I believe I can make up for it by providing a solution that could limit issues encountered by users on your site.
Plupload contains a setting that will retry the upload upon encountering a HTTP error response. Use the max_retries setting so that in an instance where there is a "network hiccup", another attempt (or few) is/are done to retry the upload. Of course you'll still see the exceptions, but this may prevent the users from having to click the upload button again.
Your code would then become:
var uploader = new plupload.Uploader({
browse_button: 'fileSelectorLink',
max_retries: 2,
container: 'uploadContainer',
drop_element: 'uploadbox',
url: '/UploadHandler.ashx',
unique_names: true,
multi_selection: false,
flash_swf_url: '/scripts/plupload/js/Moxie.swf',
silverlight_xap_url: '/scripts/plupload/js/Moxie.xap'
});
Additionally, you can use a binary stream instead of multipart to post the file, which may alleviate issues with older browsers. You control this with the multipart setting.
I have a WebForms app that uses the WindowsAzure.Storage API v3. It works fine in development and in one production environment, but I'm rolling out a new instance and any code that calls out Azure Blob Storage gives me a 403 error.
I've been fiddling with this for awhile, and it fails on any call out to Blob Storage, so rather than show my code I'll show my stack trace:
[WebException: The remote server returned an error: (403) Forbidden.]
System.Net.HttpWebRequest.GetResponse() +8525404
Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync(RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) +1541
[StorageException: The remote server returned an error: (403) Forbidden.]
Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync(RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) +2996
Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer.CreateIfNotExists(BlobContainerPublicAccessType accessType, BlobRequestOptions requestOptions, OperationContext operationContext) +177
ObsidianData.Azure.Storage.GetContainer(CloudBlobClient client, Containers targetContainer) in D:\Dev\nSource\Obsidian\Source\ObsidianData\Azure\Storage.vb:84
ObsidianWeb.Leads.HandleListenLink(String fileName, HyperLink link) in D:\Dev\nSource\Obsidian\Source\ObsidianWeb\Bdc\Leads.aspx.vb:188
ObsidianWeb.Leads.LoadEntity_ContactDetails(BoLead lead) in D:\Dev\nSource\Obsidian\Source\ObsidianWeb\Bdc\Leads.aspx.vb:147
ObsidianWeb.Leads.LoadEntity(BoLead Lead) in D:\Dev\nSource\Obsidian\Source\ObsidianWeb\Bdc\Leads.aspx.vb:62
EntityPages.EntityPage`1.LoadEntity() +91
EntityPages.EntityPage`1.Page_LoadComplete(Object sender, EventArgs e) +151
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4018
Here's what I've tried...
The AzureStorageConnectionString that fails in this environment definitely works in production
Other connection strings (from the other production environment, which works) also get a 403 here
There seemed to be an issue with timestamps in some old versions of the REST api (which I am not directly using...) so I made certain the times are correct, even tried switching the server to UTC time.
Tried toggling the connection string between http/https.
Upgraded to the latest version of the API (v3.1)
Tried fiddling with the code to ensure that every call out to Azure Storage gets 403. It does.
In desperation, Installed Azure Powershell on the server just to verify that some type of communication with Azure is working. And that worked fine.
Browsed to the azure management portal as well and that works fine.
Any ideas? This should just be using port 80 or 443, right? So there should be no way this is some kind of network issue. Let me know if that's wrong.
The working production machine is an Azure VM (Server 2008 R2 with IIS 7.5)
There are also some differences with the server:
This new machine is physical hardware (Server 2012 and IIS 8)
This IS using a different storage account inside my azure subscription, however I've tried a total of 3 connection strings and none of them work here.
UPDATE: someone asked to see the code. Okay, I wrote a class called Azure.Storage, which just abstracts my cloud storage code. We are failing on a call to Storage.Exists, so here's the part of that class that feels relevant:
Public Shared Function Exists(container As Containers, blobName As String) As Boolean
Dim Dir As CloudBlobContainer = GetContainer(container)
Dim Blob As CloudBlockBlob = Dir.GetBlockBlobReference(blobName.ToLower())
Return Blob.Exists()
End Function
Private Shared Function GetContainer(client As CloudBlobClient, targetContainer As Containers)
Dim Container As CloudBlobContainer = client.GetContainerReference(targetContainer.ToString.ToLower())
Container.CreateIfNotExists()
Container.SetPermissions(New BlobContainerPermissions() With {.PublicAccess = BlobContainerPublicAccessType.Blob})
Return Container
End Function
Private Shared Function GetCloudBlobClient() As CloudBlobClient
Dim Account As CloudStorageAccount = CloudStorageAccount.Parse(Settings.Cloud.AzureStorageConnectionString())
Return Account.CreateCloudBlobClient()
End Function
...Containers is just an enum of container names (there are several):
Public Enum Containers
CallerWavs
CampaignImports
Delve
Exports
CampaignImages
Logos
ReportLogos
WebLinkImages
End Enum
...Yes, they have upper-case characters, which causes problems. Everything is forced to lowercase before it goes out.
Also I did verify that the correct AzureConnectionString is coming out of my settings class. Again, I tried a few that work elsewhere. And this one works elsewhere also!
Please check the clock on the servers in question. Apart from the incorrect account key, you can also get 403 error if the time on the server is not in sync with the time on storage servers (Give or take +/- 15 minutes deviation is allowed).
I also ran into this error. My problem was that I had turned ON dynamic IP security restrictions in my web.config and the number of files being downloaded in some cases (e.g. with pages with lots of images) was exceeding the max thresholds I had defined in my web.config.
In my case Access key is not same as connection string using by the source code.
So try to recheck on your Azure -> [Storage Account Name] -> Access Keys -> key1 -> Key & Connection string.
I'm trying to start a new process from my WCF Service. For that purpose I use
var process = Process.Start(
new ProcessStartInfo { WorkingDirectory = config.WorkingDirectory,
FileName = config.WorkingDirectory,
Arguments = string.Format("{0} {1}", mpcName, jobId),
CreateNoWindow = false,
WindowStyle = ProcessWindowStyle.Hidden });
The WebApp is using a separate AppDomain whose Identity is set to a user account having administrator rights on the server.
Process.Start throws an exception telling
Server execution failed, at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
I also tested setting user and password in ProcessStartInfo. Specifying the password was quite tricky (SecureString) and then I received
The stub received bad data, at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
so I skipped this way.
Do you know what is the reason for my problem and how I can fix it.
I forgot: I'm using Windows Server 2008 R2, IIS 7
I got it!
It's very strange but the only change needed was to invoke
Process.Start(exeFullPath, args);
Obviously the combination of ProcessStartInfo props is important.
This q/a helped me fix this issue in one of my projects, but different cause --
was trying to start process as a Domain user from an integration test being run by nCrunch. Turns out MY problem was a really long argument string.
(same argument string works with no user/password)
Environment is Windows 8, 64 bit.
Anyway, just gonna have to pass the arg data a different way.