We've created a custom webservice in Umbraco to add (async) files and upload them. After upload the service is called with node and file-information to add a new node to the content tree.
At first our main problem was that the service was running outside of the Umbraco context, giving strange errors with get_currentuser.
Now, we inherit the umbraco BaseWebService from the umbraco.webservices dll and we've set all acces information in the settings file; we authenticatie before doing anything else using (correct and ugly-hardcoded) administrator.
When we now execute the webservice (from the browser or anything else) we get:
at umbraco.DataLayer.SqlHelper`1.ExecuteReader(String commandText, IParameter[] parameters)
at umbraco.cms.businesslogic.CMSNode.setupNode()
at umbraco.cms.businesslogic.web.Document.setupNode()
at umbraco.cms.businesslogic.CMSNode..ctor(Int32 Id)
at umbraco.cms.businesslogic.Content..ctor(Int32 id)
at umbraco.cms.businesslogic.web.Document..ctor(Int32 id)
at FileUpload.AddDocument(String ProjectID, String NodeID, String FileName)*
Where AddDocument is our method. The node (filename w/o extension) does not exist in the tree (not anywhere, it's a new filename/node). We've cleared the recycle bin, so it's not in there either.
Are we missing something vital, does anyone has a solution?
Below is the source for the webservice;
using umbraco.cms.businesslogic.web;
using umbraco.BusinessLogic;
using umbraco.presentation.nodeFactory;
using umbraco.cms.businesslogic.member;
using umbraco.cms;
/// <summary>
/// Summary description for FileUpload
/// </summary>
[WebService(Namespace = "http://umbraco.org/webservices/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class FileUpload : umbraco.webservices.BaseWebService //System.Web.Services.WebService
{
private string GetMimeType(string fileName)
{
string mimeType = "application/unknown";
string ext = System.IO.Path.GetExtension(fileName).ToLower();
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
if (regKey != null && regKey.GetValue("Content Type") != null)
mimeType = regKey.GetValue("Content Type").ToString();
return mimeType;
}
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
[WebMethod]
public void AddDocument(string ProjectID, string NodeID, string FileName)
{
Authenticate("***", "***");
string MimeType = GetMimeType(FileName); //"application/unknown";
// Create node
int nodeId = 1197;
string fileName = System.IO.Path.GetFileNameWithoutExtension(#"*****\Upload\" + FileName);
string secGroups = "";
//EDIT DUE TO COMMENT: Behavior remains the same though
Document node = umbraco.cms.businesslogic.web.Document.MakeNew(fileName.Replace(".", ""), new DocumentType(1049), umbraco.BusinessLogic.User.GetUser(0), nodeId);
secGroups = "Intern";
StreamWriter sw = null;
try
{
//EXCEPTION IS THROWN SOMEWHERE HERE
Document doc = NodeLevel.CreateNode(fileName, "Bestand", nodeId);
doc.getProperty("bestandsNaam").Value = fileName;
byte[] buffer = System.IO.File.ReadAllBytes(#"****\Upload\" + FileName);
int projectId = 0;
int tempid = nodeId;
//EXCEPTION IS THROWN TO THIS POINT (SEE BELOW)
try
{
Access.ProtectPage(false, doc.Id, 1103, 1103);
Access.AddMembershipRoleToDocument(doc.Id, secGroups);
}
catch (Exception ex)
{
// write to file
}
try
{
doc.Publish(umbraco.BusinessLogic.User.GetUser(0));
umbraco.library.UpdateDocumentCache(doc.Id);
umbraco.content.Instance.RefreshContentFromDatabaseAsync();
}
catch (Exception ex)
{
// write to file
}
System.IO.File.Delete(FileName);
}
catch (Exception ex)
{
// THIS EXCEPTION IS CAUGHT!!
}
}
public override umbraco.webservices.BaseWebService.Services Service
{
get { return umbraco.webservices.BaseWebService.Services.DocumentService; }
}
}
If anyone has a solution, pointer, hint or whatever; help is appreciated!!
TIA,
riffnl
We've rewritten the whole procedure (dumped all code and restart) and we've got it working now.
I think we've been messing around with the old code so much in trying to get it to work we were missing some key issues, because it functions.
Thanks for thinking along anyway!
Related
I have three solution configurations in my UWP solution in Visual Studio:
Development
Staging
Production
Each is a associated with a different web service and auth provider in the configuration files. In my code, how do I tell which one is which? In the past I've explicitly provided DEFINE constants, but there must be a better way by now.
The active solution configuration is stored in the .suo file beneath the .vs directory at the root solution folder. The .suo file has a compound file binary format, which means you can't just parse it with text manipulation tools.
However, using OpenMcdf -- a tool that can be used to manipulate these types of files -- you can easily get the active solution configuration.
Here's a console app I wrote that works. Feel free to adapt the code to your situation:
using OpenMcdf;
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace GetActiveBuildConfigFromSuo
{
internal enum ProgramReturnCode
{
Success = 0,
NoArg = -1,
InvalidFileFormat = -2
}
internal class Program
{
private const string SolutionConfigStreamName = "SolutionConfiguration";
private const string ActiveConfigTokenName = "ActiveCfg";
internal static int Main(string[] args)
{
try
{
ValidateCommandLineArgs(args);
string activeSolutionConfig = ExtractActiveSolutionConfig(
new FileInfo(args.First()));
throw new ProgramResultException(
activeSolutionConfig, ProgramReturnCode.Success);
}
catch (ProgramResultException e)
{
Console.Write(e.Message);
return (int)e.ReturnCode;
}
}
private static void ValidateCommandLineArgs(string[] args)
{
if (args.Count() != 1) throw new ProgramResultException(
"There must be exactly one command-line argument, which " +
"is the path to an input Visual Studio Solution User " +
"Options (SUO) file. The path should be enclosed in " +
"quotes if it contains spaces.", ProgramReturnCode.NoArg);
}
private static string ExtractActiveSolutionConfig(FileInfo fromSuoFile)
{
CompoundFile compoundFile;
try { compoundFile = new CompoundFile(fromSuoFile.FullName); }
catch (CFFileFormatException)
{ throw CreateInvalidFileFormatProgramResultException(fromSuoFile); }
if (compoundFile.RootStorage.TryGetStream(
SolutionConfigStreamName, out CFStream compoundFileStream))
{
var data = compoundFileStream.GetData();
string dataAsString = Encoding.GetEncoding("UTF-16").GetString(data);
int activeConfigTokenIndex = dataAsString.LastIndexOf(ActiveConfigTokenName);
if (activeConfigTokenIndex < 0)
CreateInvalidFileFormatProgramResultException(fromSuoFile);
string afterActiveConfigToken =
dataAsString.Substring(activeConfigTokenIndex);
int lastNullCharIdx = afterActiveConfigToken.LastIndexOf('\0');
string ret = afterActiveConfigToken.Substring(lastNullCharIdx + 1);
return ret.Replace(";", "");
}
else throw CreateInvalidFileFormatProgramResultException(fromSuoFile);
}
private static ProgramResultException CreateInvalidFileFormatProgramResultException(
FileInfo invalidFile) => new ProgramResultException(
$#"The provided file ""{invalidFile.FullName}"" is not a valid " +
$#"SUO file with a ""{SolutionConfigStreamName}"" stream and an " +
$#"""{ActiveConfigTokenName}"" token.", ProgramReturnCode.InvalidFileFormat);
}
internal class ProgramResultException : Exception
{
internal ProgramResultException(string message, ProgramReturnCode returnCode)
: base(message) => ReturnCode = returnCode;
internal ProgramReturnCode ReturnCode { get; }
}
}
Download DTE nuget packages : EnvDTE.8.0.2
Add below code
EnvDTE.DTE DTE = Marshal.GetActiveObject("VisualStudio.DTE.15.0") as EnvDTE.DTE;
var activeConfig = (string)DTE.Solution.Properties.Item("ActiveConfig").Value;
I'm trying to create Internal Accounts programmaticaly by using proc metadata.
The code section below creates person with External Login.
put"<Person Name=%str(%')&&PersonName&i.%str(%')>";
put"<Logins>";
put"<Login Name=%str(%')Login.&&PersonName&i.%str(%') Password=%str(%')&&word&i.%str(%')/>";
put"</Logins>";
put"</Person>";
To create ExternalLogin we can set attribute Password, and in SAS Metadata it will be encrypted automaticaly.
But to create InternalLogin type of object it is necessary to make the hash value of the password and the salt. I know that the standard sas002 encryption method, but in the case of using proc pwencode how to obtain the value of salt?
Is it possible create InternalLogin by using SAS Base?
Thanx.
So on. I found an article that can tell us how to create Stored Process for this problem. My answer is addition to the article.
The approach is base on execute java methods from sas programm.
1. Prerare setPasswd.java class
I've modified class from article. Separate code to connect to metadata server and create InternalLogin
import java.rmi.RemoteException;
import com.sas.metadata.remote.AssociationList;
import com.sas.metadata.remote.CMetadata;
import com.sas.metadata.remote.Person;
import com.sas.metadata.remote.MdException;
import com.sas.metadata.remote.MdFactory;
import com.sas.metadata.remote.MdFactoryImpl;
import com.sas.metadata.remote.MdOMIUtil;
import com.sas.metadata.remote.MdOMRConnection;
import com.sas.metadata.remote.MdObjectStore;
import com.sas.metadata.remote.MetadataObjects;
import com.sas.metadata.remote.PrimaryType;
import com.sas.metadata.remote.Tree;
import com.sas.meta.SASOMI.ISecurity_1_1;
import com.sas.iom.SASIOMDefs.VariableArray2dOfStringHolder;
public class setPasswd {
String serverName = null;
String serverPort = null;
String serverUser = null;
String serverPass = null;
MdOMRConnection connection = null;
MdFactoryImpl _factory = null;
ISecurity_1_1 iSecurity = null;
MdObjectStore objectStore = null;
Person person = null;
public int connectToMetadata(String name, String port, String user, String pass){
try {
serverName = name;
serverPort = port;
serverUser = user;
serverPass = pass;
_factory = new MdFactoryImpl(false);
connection = _factory.getConnection();
connection.makeOMRConnection(serverName, serverPort, serverUser, serverPass);
iSecurity = connection.MakeISecurityConnection();
return 0;
}catch(Exception e){
return 1;
}
}
public setPasswd(){};
public int changePasswd(String IdentityName, String IdentityPassword) {
try
{
//
// This block obtains the person metadata ID that is needed to change the password
//
// Defines the GetIdentityInfo 'ReturnUnrestrictedSource' option.
final String[][] options ={{"ReturnUnrestrictedSource",""}};
// Defines a stringholder for the info output parameter.
VariableArray2dOfStringHolder info = new VariableArray2dOfStringHolder();
// Issues the GetInfo method for the provided iSecurity connection user.
iSecurity.GetInfo("GetIdentityInfo","Person:"+IdentityName, options, info);
String[][] returnArray = info.value;
String personMetaID = new String();
for (int i=0; i< returnArray.length; i++ )
{
System.out.println(returnArray[i][0] + "=" + returnArray[i][1]);
if (returnArray[i][0].compareTo("IdentityObjectID") == 0) {
personMetaID = returnArray[i][1];
}
}
objectStore = _factory.createObjectStore();
person = (Person) _factory.createComplexMetadataObject(objectStore, IdentityName, MetadataObjects.PERSON, personMetaID);
iSecurity.SetInternalPassword(IdentityName, IdentityPassword);
person.updateMetadataAll();
System.out.println("Password has been changed.");
return 0; // success
}
catch (MdException e)
{
Throwable t = e.getCause();
if (t != null)
{
String ErrorType = e.getSASMessageSeverity();
String ErrorMsg = e.getSASMessage();
if (ErrorType == null)
{
// If there is no SAS server message, write a Java/CORBA message.
}
else
{
// If there is a message from the server:
System.out.println(ErrorType + ": " + ErrorMsg);
}
if (t instanceof org.omg.CORBA.COMM_FAILURE)
{
// If there is an invalid port number or host name:
System.out.println(e.getLocalizedMessage());
}
else if (t instanceof org.omg.CORBA.NO_PERMISSION)
{
// If there is an invalid user ID or password:
System.out.println(e.getLocalizedMessage());
}
}
else
{
// If we cannot find a nested exception, get message and print.
System.out.println(e.getLocalizedMessage());
}
// If there is an error, print the entire stack trace.
e.printStackTrace();
}
catch (RemoteException e)
{
// Unknown exception.
e.printStackTrace();
}
catch (Exception e)
{
// Unknown exception.
e.printStackTrace();
}
System.out.println("Failure: Password has NOT been changed.");
return 1; // failure
}
}
2. Resolve depends
Pay attention to imports in class. To enable execute the code below necessary set CLASSPATH enironment variable.
On linux you can add the next command in %SASConfig%/Lev1/level_env_usermods.sh:
export CLASSPATH=$CLASSPATH:%pathToJar%
On Windows you can add/change environment variable by Advanced system settings
So where should you search jar files? They are in folder:
%SASHome%/SASVersionedJarRepository/eclipse/plugins/
Which files i should include in path?
I've include all that used in OMI(Open Metadata Interface).Also I've added log4j.jar (not working without this jar. Your promts will be helpful):
sas.oma.joma.jar
sas.oma.joma.rmt.jar
sas.oma.omi.jar
sas.svc.connection.jar
sas.core.jar
sas.entities.jar
sas.security.sspi.jar
log4j.jar
setPasswd.jar (YOUR JAR FROM THE NEXT STEP!)
Choose files from nearest release. Example:
Here I'm set file from v940m3f (fix release).
Other ways is here.
3. Compile setPasswd.jar
I'm tried use internal javac.exe into SAS, but it's not worked properly. So ou need to download JDK to compile jars. I've create Bat-file:
"C:\Program Files\Java\jdk1.8.0_121\bin\javac.exe" -source 1.7 -target 1.7 setPasswd.java
"C:\Program Files\Java\jdk1.8.0_121\bin\jar" -cf setPasswd.jar setPasswd.class
Paramethers -source and -target will helpful if your version of JDK is upper, that usses in SAS. Version of "sas"-java you can see by:
PROC javainfo all;
run;
Search the next string in log:
java.vm.specification.version = 1.7
4. Finally. SAS Base call
Now we can call Java code by this method (All methods available here):
data test;
dcl javaobj j ("setPasswd");
j.callIntMethod("connectToMetadata", "%SERVER%", "%PORT%", "%ADMIN%", "%{SAS002}HASHPASSORPASS%", rc1);
j.callIntMethod("changePasswd", "testPassLogin", "pass1", rc2);
j.delete();
run;
In log:
UserClass=Normal
AuthenticatedUserid=Unknown
IdentityName=testPass
IdentityType=Person
IdentityObjectID=A56RQPC2.AP00000I
Password has been changed.
Now time to test. Create new user with no passwords.
Execute code:
data test;
dcl javaobj j ("setPasswd");
j.callIntMethod("connectToMetadata", "&server.", "&port.", "&adm", "&pass", rc1);
j.callIntMethod("changePasswd", "TestUserForStack", "Overflow", rc2);
j.delete();
run;
Now our user has InternalLogin object.
Thanx.
I am trying to send a string to the EventHub and I have written this code:
private static void sendPOST(ValueChangeMessage valueChangeMessage) throws IOException {
try {
// final String namespaceName = ""; //sericebusnamespacename
// final String eventHubName = "";
// final String sasKeyName = "";
// final String sasKey = "";
// ConnectionStringBuilder connStr = new ConnectionStringBuilder(namespaceName, eventHubName, sasKeyName, sasKey);
byte[] payloadBytes = valueChangeMessage.data.get().toString().getBytes(StandardCharsets.UTF_8);
EventData sendEvent = new EventData(payloadBytes);
EventHubClient ehClient = EventHubClient.createFromConnectionStringSync(connStr.toString());
ehClient.sendSync(sendEvent);
}
catch (ServiceBusException ex) {
Logger.getLogger(CatChannel.class.getName()).log(Level.SEVERE, null, ex);
}
}
But whenever I try to run the project from netbeans , it
gives the error below:
error: cannot access Message
sendEvent = new EventData(payloadBytes);
class file for org.apache.qpid.proton.message.Message not found
Can anyone tell me what can be the possible issue??
I got the fix for this..........actually the issue was with the proxies of the system.....it wasnt able to download the jars from maven.....So i manually included the dependencies in my project
I'm working with a project, where I have EMF model 'A' which is referenced in many other models 'B','C'... etc. What I want is I want to give a rename feature for these resources. So when user renames 'A', its references have to be updated.
Please provide some idea on it, if there is any frame work for this or I have to get all the references and then programmatically iterate and update the references.
I solved the same problem in another way.
The fundamental problem is that a referenced resource file might be renamed, and this breaks the references.
Instead of a refactoring that automatically updates all references I created a Repair File References command, which the user can invoke on an edited model.
The command performs these steps:
Prompts the user to select a missing resource to repair
Prompts the user to select a replacement file
Updates all objects in the model that has a proxy URI that matches the missing resource. Replaces proxies with resolved objects in the new resource.
If you still want to make a refactoring instead, I think you anyway can use my code as a starting point.
/**
* Locates and fixes unresolved references in a model.
*/
public class ReferenceRepairer {
public static final String COMMAND_ID = Activator.PLUGIN_ID + ".commands.repairReferences";
/**
* 1) Prompts the user to select a missing resource to repair
* 2) Prompts the user to select a replacement file
* 3) Updates all objects in the model with a proxy URI that matches the missing resource. Replaces proxies
* with resolved objects in the new resource.
*/
public static void repairResourceReference(Shell shell, EditingDomain editingDomain) {
Resource res = promptMissingResource(shell, editingDomain);
if (res == null) return;
IFile newFile = promptReplacementFile(shell);
if (newFile == null) return;
repairReferences(editingDomain, res, URI.createPlatformResourceURI(newFile.getFullPath().toString(), true));
}
private static void repairReferences(final EditingDomain editingDomain, Resource missingRes, final URI newUri) {
URI missingUri = missingRes.getURI();
// Create new resource for the replacement file
Resource newRes = editingDomain.getResourceSet().getResource(newUri, true);
Map<EObject, Collection<Setting>> proxies = UnresolvedProxyCrossReferencer.find(editingDomain.getResourceSet());
CompoundCommand repairRefsCommand = new CompoundCommand("Repair references") {
/**
* Disallow undo. The model changes could be undone, but it seems impossible to
* recreate a non-existent resource in the resource set.
*/
#Override
public boolean canUndo() {
return false;
}
};
// Resolve all proxies from this resource and repair reference to those objects
for (Entry<EObject, Collection<Setting>> entry : proxies.entrySet()) {
EObject proxy = entry.getKey();
URI proxyUri = EcoreUtil.getURI(proxy);
if (!proxyUri.trimFragment().equals(missingUri)) continue;
EObject resolved = newRes.getEObject(proxyUri.fragment());
if (resolved.eIsProxy()) continue;
// Update all objects that have references to the resolved proxy
for (Setting sett : entry.getValue()) {
if (sett.getEStructuralFeature().isMany()) {
#SuppressWarnings("unchecked")
EList<Object> valueList = (EList<Object>) sett.get(true);
int proxyIx = valueList.indexOf(proxy);
repairRefsCommand.append(SetCommand.create(editingDomain,
sett.getEObject(), sett.getEStructuralFeature(), resolved, proxyIx));
} else {
repairRefsCommand.append(SetCommand.create(editingDomain,
sett.getEObject(), sett.getEStructuralFeature(), resolved));
}
}
}
if (!repairRefsCommand.isEmpty()) {
editingDomain.getCommandStack().execute(repairRefsCommand);
}
// Remove the
editingDomain.getResourceSet().getResources().remove(missingRes);
}
private static IFile promptReplacementFile(Shell shell) {
ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(shell,
new WorkbenchLabelProvider(), new WorkbenchContentProvider());
dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
dialog.setTitle("Select Replacement Resource");
dialog.setMessage("Select a file which will replace the missing file.");
dialog.setValidator(new ISelectionStatusValidator() {
#Override
public IStatus validate(Object[] selection) {
if (selection.length == 0 || !(selection[0] instanceof IFile)) {
return ValidationStatus.error("The selected object is not a file.");
}
return new Status(IStatus.OK, Activator.PLUGIN_ID, "");
}
});
if (dialog.open() != Window.OK) return null;
return (IFile) dialog.getFirstResult();
}
private static Resource promptMissingResource(Shell shell, EditingDomain editingDomain) {
ElementListSelectionDialog dialog = new ElementListSelectionDialog(shell,
new LabelProvider() {
#Override
public String getText(Object elem) {
return ((Resource) elem).getURI().toString();
}
})
{
/** Make dialog OK button enabled when there are errors, instead of vise-versa. */
#Override
protected void updateButtonsEnableState(IStatus status) {
Button okButton = getOkButton();
if (okButton != null && !okButton.isDisposed()) {
okButton.setEnabled(!status.isOK());
}
}
/** Disable filter text field */
#Override
protected Text createFilterText(Composite parent) {
Text text = super.createFilterText(parent);
text.setSize(0, 0);
text.setLayoutData(GridDataFactory.swtDefaults().exclude(true).create());
text.setVisible(false);
return text;
}
};
dialog.setTitle("Select Missing Resource");
dialog.setMessage(
"Select a URI of a missing resource file that should be replaced by an URI to an existing file.");
dialog.setElements(getMissingResources(editingDomain.getResourceSet().getResources()).toArray());
if (dialog.open() != Window.OK) return null;
return (Resource) dialog.getFirstResult();
}
private static List<Resource> getMissingResources(List<Resource> resources) {
List<Resource> missingResources = new ArrayList<>();
for (Resource res : resources) {
try {
if (res.getURI().isPlatformPlugin()) continue;
URL url = FileLocator.toFileURL(new URL(res.getURI().toString()));
java.net.URI uri = new java.net.URI(url.getProtocol(), "", "/" + url.getPath(), null);
if (!Files.exists(Paths.get(uri))) {
missingResources.add(res);
}
} catch (InvalidPathException | IOException | URISyntaxException exc) {
// Ignore. There mighe be weird Sirius resource in the resources set which we can't recognice
}
}
return missingResources;
}
}
Searched quite a bit. The problem with these errors is that while the text might appear the same, the problem is always different.
My service takes ONE string value and returns a string response. Here is my code:
private class UploadStats extends AsyncTask<String, Void, String>
{
private static final String WSDL_TARGET_NAMESPACE = "http://tempuri.org/";
private static final String SOAP_ADDRESS = "http://192.168.1.101/rss/RSS_Service.asmx?WSDL";
private static final String INSERTURLACTION = "http://192.168.1.101/rss/RSS_Service.asmx/InsertURL";
private static final String INSERTURLMETHOD = "InsertURL";
#Override
protected String doInBackground(String... url)
{
String status = "";
SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE,
INSERTURLMETHOD);
request.addProperty("url", "www.yahoo.com");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);
try
{
httpTransport.call(INSERTURLACTION, envelope);
SoapObject response = (SoapObject) envelope.bodyIn;
status = response.getProperty(0).toString();
}
catch (Exception exception)
{
Log.d("Error", exception.toString());
}
if(status.equals("1"))
{
Log.d("InsertURL", "New URL Inserterd");
}
else if(status.equals("0"))
{
Log.d("InsertURL", "URL Exists. Count incremented");
}
else
{
Log.d("InsertURL", "Err... No");
}
return status;
}
}
I get the error:
java.lang.classcastexception org.ksoap2.SoapFault
What am I doing wrong? If any more details are needed, I can add them.
The error was related to the webservice.
An incorrect namespace on the service side can cause this error (as can a lot of other problems).
Best way to check is to run the webservice on the local machine (where the service is hosted).