///<summary>Pass in a serialized dto. It returns a dto which must be deserialized by the client. ///Set serverMapPath to the root directory of the OpenDentalServerConfig.xml. Typically Server.MapPath(".") from a web service. ///Optional parameter because it is not necessary for Unit Tests (mock server).</summary> public static string ProcessDto(string dtoString, string serverMapPath = "") { try { #region Normalize DateTime if (!_isMiddleTierInitialized) { //If this fails, the exception will throw and be serialized and sent to the client. ODInitialize.Initialize(); //Because Security._curUserT is a thread static field, we need to make sure that any new threads that are spawned have that field set. ODThread.AddInitializeHandler <Userod>(() => Security.CurUser.Copy(), user => Security.CurUser = user); //Same thing for PasswordTyped. ODThread.AddInitializeHandler <string>(() => Security.PasswordTyped, password => Security.PasswordTyped = password); //Ditto for CurComputerName ODThread.AddInitializeHandler <string>(() => Security.CurComputerName, computerName => Security.CurComputerName = computerName); //Calling CDT.Class1.Decrypt will cause CDT to verify the assembly and then save the encryption key. This needs to be done here because //if we later call CDT.Class1.Decrypt inside a thread, we won't we able to find OpenDentalServer.dll in the call stack. ODException.SwallowAnyException(() => CDT.Class1.Decrypt("odv2e$fakeciphertext", out _)); _isMiddleTierInitialized = true; } #endregion #region Initialize Database Connection //Always attempt to set the database connection settings from the config file if they haven't been set yet. //We use to ONLY load in database settings when Security.LogInWeb was called but that is not good enough now that we have more services. //E.g. We do not want to manually call "Security.LogInWeb" from the CEMT when all we want is a single preference value. if (string.IsNullOrEmpty(DataConnection.GetServerName()) && string.IsNullOrEmpty(DataConnection.GetConnectionString())) { RemotingClient.RemotingRole = RemotingRole.ServerWeb; //the application virtual path is usually /OpenDentalServer, but may be different if hosting multiple databases on one IIS server string configFilePath = ""; if (!string.IsNullOrWhiteSpace(HostingEnvironment.ApplicationVirtualPath) && HostingEnvironment.ApplicationVirtualPath.Length > 1) { //There can be multiple config files within a physical path that is shared by multiple IIS ASP.NET applications. //In order for the same physical path to host multiple applications, they each need a unique config file for db connection settings. //Each application will have a unique ApplicationVirtualPath which we will use to identify the corresponding config.xml. configFilePath = ODFileUtils.CombinePaths(serverMapPath, HostingEnvironment.ApplicationVirtualPath.Trim('/') + "Config.xml"); } if (string.IsNullOrWhiteSpace(configFilePath) || !File.Exists(configFilePath)) //returns false if the file doesn't exist, user doesn't have permission for file, path is blank or null { //either configFilePath not set or file doesn't exist, default to OpenDentalServerConfig.xml configFilePath = ODFileUtils.CombinePaths(serverMapPath, "OpenDentalServerConfig.xml"); } Userods.LoadDatabaseInfoFromFile(configFilePath); } #endregion DataTransferObject dto = DataTransferObject.Deserialize(dtoString); DtoInformation dtoInformation = new DtoInformation(dto); if (dtoInformation.FullNameComponents.Length == 3 && dtoInformation.FullNameComponents[2].ToLower() == "hashpassword") { return(dtoInformation.GetHashPassword()); } //Set Security.CurUser so that queries can be run against the db as if it were this user. Security.CurUser = Userods.CheckUserAndPassword(dto.Credentials.Username, dto.Credentials.Password , Programs.UsingEcwTightOrFullMode()); Security.PasswordTyped = dto.Credentials.Password; //Set the computer name so securitylog entries use the client's computer name instead of the middle tier server name //Older clients might not include ComputerName in the dto, so we need to make sure it's not null. Security.CurComputerName = dto.ComputerName ?? ""; Type type = dto.GetType(); #region DtoGetTable if (type == typeof(DtoGetTable)) { DataTable dt = (DataTable)dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); return(XmlConverter.TableToXml(dt)); } #endregion #region DtoGetTableLow else if (type == typeof(DtoGetTableLow)) { DataTable dt = Reports.GetTable((string)dtoInformation.ParamObjs[0]); return(XmlConverter.TableToXml(dt)); } #endregion #region DtoGetDS else if (type == typeof(DtoGetDS)) { DataSet ds = (DataSet)dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); return(XmlConverter.DsToXml(ds)); } #endregion #region DtoGetSerializableDictionary else if (type == typeof(DtoGetSerializableDictionary)) { Object objResult = dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); Type returnType = dtoInformation.MethodInfo.ReturnType; return(XmlConverterSerializer.Serialize(returnType, objResult)); } #endregion #region DtoGetLong else if (type == typeof(DtoGetLong)) { long longResult = (long)dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); return(longResult.ToString()); } #endregion #region DtoGetInt else if (type == typeof(DtoGetInt)) { int intResult = (int)dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); return(intResult.ToString()); } #endregion #region DtoGetDouble else if (type == typeof(DtoGetDouble)) { double doubleResult = (double)dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); return(doubleResult.ToString()); } #endregion #region DtoGetVoid else if (type == typeof(DtoGetVoid)) { dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); return("0"); } #endregion #region DtoGetObject else if (type == typeof(DtoGetObject)) { if (dtoInformation.ClassName == "Security" && dtoInformation.MethodName == "LogInWeb") { dtoInformation.Parameters[2] = new DtoObject(serverMapPath, typeof(string)); //because we can't access this variable from within OpenDentBusiness. RemotingClient.RemotingRole = RemotingRole.ServerWeb; //We just changed the number of parameters so we need to regenerate ParamObjs. dtoInformation.ParamObjs = DtoObject.GenerateObjects(dtoInformation.Parameters); } Object objResult = dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); Type returnType = dtoInformation.MethodInfo.ReturnType; if (returnType.IsInterface) { objResult = new DtoObject(objResult, objResult?.GetType() ?? returnType); returnType = typeof(DtoObject); } return(XmlConverterSerializer.Serialize(returnType, objResult)); } #endregion #region DtoGetString else if (type == typeof(DtoGetString)) { string strResult = (string)dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); return(XmlConverter.XmlEscape(strResult)); } #endregion #region DtoGetBool else if (type == typeof(DtoGetBool)) { bool boolResult = (bool)dtoInformation.MethodInfo.Invoke(null, dtoInformation.ParamObjs); return(boolResult.ToString()); } #endregion else { throw new NotSupportedException("Dto type not supported: " + type.FullName); } } catch (Exception e) { DtoException exception = new DtoException(); if (e.InnerException == null) { exception = GetDtoException(e); } else { exception = GetDtoException(e.InnerException); } return(exception.Serialize()); } }