I have already configured my Azure SQL Server so that I am Server admin, my account also has MFA enabled. I was trying to follow this documentation but it doesn't mention anything about Active directory with MFA.
I can use my account and MFA to sign into the server fine using SQL Management studio
Initially I tried (based on the new SqlAuthenticationMethod Enum):
SqlConnection con = new SqlConnection("Server=tcp:myapp.database.windows.net;Database=CustomerDB;Authentication=Active Directory Interactive;Encrypt=True;UID=User#User.co.uk"))
Error:
'Cannot find an authentication provider for
'ActiveDirectoryInteractive'.'
I then saw this about accessing SQL via an Azure application But this is not what I want to do.
This SO question talks about connecting without the provider and setting the Driver in the connection string
SqlConnection con = new SqlConnection("DRIVER={ODBC Driver 17 for SQL Server};Server=tcp:myapp.database.windows.net;Database=CustomerDB;Authentication=Active Directory Interactive;Encrypt=True;UID=User#User.co.uk"))
but I get the error:
'Keyword not supported: 'driver'.'
Is there anyway to write a connection string so that when it tries to connect the Microsoft authentication box pops up to walk the user through Multi factor authentication?
To use Azure AD authentication, your C# program has to register as an Azure AD application. Completing an app registration generates and displays an application ID. Your program has to include this ID to connect. To register and set necessary permissions for your application, go to the Azure portal, select Azure Active Directory > App registrations > New registration.
After the app registration is created, the application ID value is generated and displayed.
Select API permissions > Add a permission.
Select APIs my organization uses > type Azure SQL Database into the search > and select Azure SQL Database.
Select Delegated permissions > user_impersonation > Add permissions.
It seems you have already set an Azure AD admin for your Azure SQL Database.
You can also add a user to the database with the SQL Create User command. An example is CREATE USER [] FROM EXTERNAL PROVIDER. For more information, see here.
Below an example on C#.
using System;
// Reference to Azure AD authentication assembly
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using DA = System.Data;
using SC = System.Data.SqlClient;
using AD = Microsoft.IdentityModel.Clients.ActiveDirectory;
using TX = System.Text;
using TT = System.Threading.Tasks;
namespace ADInteractive5
{
class Program
{
// ASSIGN YOUR VALUES TO THESE STATIC FIELDS !!
static public string Az_SQLDB_svrName = "<Your SQL DB server>";
static public string AzureAD_UserID = "<Your User ID>";
static public string Initial_DatabaseName = "<Your Database>";
// Some scenarios do not need values for the following two fields:
static public readonly string ClientApplicationID = "<Your App ID>";
static public readonly Uri RedirectUri = new Uri("<Your URI>");
public static void Main(string[] args)
{
var provider = new ActiveDirectoryAuthProvider();
SC.SqlAuthenticationProvider.SetProvider(
SC.SqlAuthenticationMethod.ActiveDirectoryInteractive,
//SC.SqlAuthenticationMethod.ActiveDirectoryIntegrated, // Alternatives.
//SC.SqlAuthenticationMethod.ActiveDirectoryPassword,
provider);
Program.Connection();
}
public static void Connection()
{
SC.SqlConnectionStringBuilder builder = new SC.SqlConnectionStringBuilder();
// Program._ static values that you set earlier.
builder["Data Source"] = Program.Az_SQLDB_svrName;
builder.UserID = Program.AzureAD_UserID;
builder["Initial Catalog"] = Program.Initial_DatabaseName;
// This "Password" is not used with .ActiveDirectoryInteractive.
//builder["Password"] = "<YOUR PASSWORD HERE>";
builder["Connect Timeout"] = 15;
builder["TrustServerCertificate"] = true;
builder.Pooling = false;
// Assigned enum value must match the enum given to .SetProvider().
builder.Authentication = SC.SqlAuthenticationMethod.ActiveDirectoryInteractive;
SC.SqlConnection sqlConnection = new SC.SqlConnection(builder.ConnectionString);
SC.SqlCommand cmd = new SC.SqlCommand(
"SELECT '******** MY QUERY RAN SUCCESSFULLY!! ********';",
sqlConnection);
try
{
sqlConnection.Open();
if (sqlConnection.State == DA.ConnectionState.Open)
{
var rdr = cmd.ExecuteReader();
var msg = new TX.StringBuilder();
while (rdr.Read())
{
msg.AppendLine(rdr.GetString(0));
}
Console.WriteLine(msg.ToString());
Console.WriteLine(":Success");
}
else
{
Console.WriteLine(":Failed");
}
sqlConnection.Close();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Connection failed with the following exception...");
Console.WriteLine(ex.ToString());
Console.ResetColor();
}
}
} // EOClass Program.
/// <summary>
/// SqlAuthenticationProvider - Is a public class that defines 3 different Azure AD
/// authentication methods. The methods are supported in the new .NET 4.7.2.
/// .
/// 1. Interactive, 2. Integrated, 3. Password
/// .
/// All 3 authentication methods are based on the Azure
/// Active Directory Authentication Library (ADAL) managed library.
/// </summary>
public class ActiveDirectoryAuthProvider : SC.SqlAuthenticationProvider
{
// Program._ more static values that you set!
private readonly string _clientId = Program.ClientApplicationID;
private readonly Uri _redirectUri = Program.RedirectUri;
public override async TT.Task<SC.SqlAuthenticationToken>
AcquireTokenAsync(SC.SqlAuthenticationParameters parameters)
{
AD.AuthenticationContext authContext =
new AD.AuthenticationContext(parameters.Authority);
authContext.CorrelationId = parameters.ConnectionId;
AD.AuthenticationResult result;
switch (parameters.AuthenticationMethod)
{
case SC.SqlAuthenticationMethod.ActiveDirectoryInteractive:
Console.WriteLine("In method 'AcquireTokenAsync', case_0 == '.ActiveDirectoryInteractive'.");
result = await authContext.AcquireTokenAsync(
parameters.Resource, // "https://database.windows.net/"
_clientId,
_redirectUri,
new AD.PlatformParameters(AD.PromptBehavior.Auto),
new AD.UserIdentifier(
parameters.UserId,
AD.UserIdentifierType.RequiredDisplayableId));
break;
case SC.SqlAuthenticationMethod.ActiveDirectoryIntegrated:
Console.WriteLine("In method 'AcquireTokenAsync', case_1 == '.ActiveDirectoryIntegrated'.");
result = await authContext.AcquireTokenAsync(
parameters.Resource,
_clientId,
new AD.UserCredential());
break;
case SC.SqlAuthenticationMethod.ActiveDirectoryPassword:
Console.WriteLine("In method 'AcquireTokenAsync', case_2 == '.ActiveDirectoryPassword'.");
result = await authContext.AcquireTokenAsync(
parameters.Resource,
_clientId,
new AD.UserPasswordCredential(
parameters.UserId,
parameters.Password));
break;
default: throw new InvalidOperationException();
}
return new SC.SqlAuthenticationToken(result.AccessToken, result.ExpiresOn);
}
public override bool IsSupported(SC.SqlAuthenticationMethod authenticationMethod)
{
return authenticationMethod == SC.SqlAuthenticationMethod.ActiveDirectoryIntegrated
|| authenticationMethod == SC.SqlAuthenticationMethod.ActiveDirectoryInteractive
|| authenticationMethod == SC.SqlAuthenticationMethod.ActiveDirectoryPassword;
}
} // EOClass ActiveDirectoryAuthProvider.
} // EONamespace. End of entire program source code.
The example above relies on the Microsoft.IdentityModel.Clients.ActiveDirectory DLL assembly.
To install this package, in Visual Studio, select Project > Manage NuGet Packages. Search for and install Microsoft.IdentityModel.Clients.ActiveDirectory.
Starting in .NET Framework version 4.7.2, the enum SqlAuthenticationMethod has a new value: ActiveDirectoryInteractive.
The only way I have found to login using Active Directory and MFA and cache the token is to use #Alberto's method
I did also find another way which would ask for login credentials every time which is to use this connection string:
OdbcConnection con = new OdbcConnection("Driver={ODBC Driver 17 for SQL Server};SERVER=tcp:myserver.database.windows.net;DATABASE=MyDb;Authentication=ActiveDirectoryInteractive;UID=User#Userco.uk")
Improving the code posted by #alberto. I must say for something so fundamental in the modern world this is unbelievably undocumented. Anyway here's the improved Provider code.
This code also requires you to target .Net Framework 4.7.2 or greater
Firstly follow #alberto's code.. I did find one extra unmentioned step is that you need to also configure a Platform for your app in azure on the authentication tab to look like:
Add these two classes to your project:
ActiveDirectoryAuthProvider
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Data.SqlClient;
namespace SQLAzureConnectivity
{
public class ActiveDirectoryAuthProvider : SqlAuthenticationProvider
{
private string _clientId { get; set; }
private Uri _redirectURL { get; set; } = new Uri("https://login.microsoftonline.com/common/oauth2/nativeclient");
public ActiveDirectoryAuthProvider(string clientId)
{
_clientId = clientId;
}
//https://learn.microsoft.com/en-us/azure/sql-database/active-directory-interactive-connect-azure-sql-db#c-code-example
public override async Task<System.Data.SqlClient.SqlAuthenticationToken> AcquireTokenAsync(System.Data.SqlClient.SqlAuthenticationParameters parameters)
{
AuthenticationContext authContext = new AuthenticationContext(parameters.Authority, new FilesBasedAdalV3TokenCache(".\\Token.dat"));
authContext.CorrelationId = parameters.ConnectionId;
AuthenticationResult result = null;
switch (parameters.AuthenticationMethod)
{
case System.Data.SqlClient.SqlAuthenticationMethod.ActiveDirectoryInteractive:
Console.WriteLine("In method 'AcquireTokenAsync', case_0 == '.ActiveDirectoryInteractive'.");
try
{
result = await authContext.AcquireTokenSilentAsync(parameters.Resource, _clientId);
}
catch (AdalException adalException)
{
if (adalException.ErrorCode == AdalError.FailedToAcquireTokenSilently || adalException.ErrorCode == AdalError.InteractionRequired)
{
result = await authContext.AcquireTokenAsync(parameters.Resource, _clientId, _redirectURL, new PlatformParameters(PromptBehavior.Auto));
//result = await authContext.AcquireTokenAsync(parameters.Resource, _clientId, _redirectURL, new PlatformParameters(PromptBehavior.Auto), new UserIdentifier(parameters.UserId, UserIdentifierType.RequiredDisplayableId));
}
}
break;
case System.Data.SqlClient.SqlAuthenticationMethod.ActiveDirectoryIntegrated:
Console.WriteLine("In method 'AcquireTokenAsync', case_1 == '.ActiveDirectoryIntegrated'.");
result = await authContext.AcquireTokenAsync(parameters.Resource, _clientId, new UserCredential());
break;
case System.Data.SqlClient.SqlAuthenticationMethod.ActiveDirectoryPassword:
Console.WriteLine("In method 'AcquireTokenAsync', case_2 == '.ActiveDirectoryPassword'.");
result = await authContext.AcquireTokenAsync(parameters.Resource, _clientId, new UserPasswordCredential(parameters.UserId, parameters.Password));
break;
default:
throw new InvalidOperationException();
}
return new System.Data.SqlClient.SqlAuthenticationToken(result.AccessToken, result.ExpiresOn);
}
public override bool IsSupported(System.Data.SqlClient.SqlAuthenticationMethod authenticationMethod)
{
return authenticationMethod == System.Data.SqlClient.SqlAuthenticationMethod.ActiveDirectoryIntegrated
|| authenticationMethod == System.Data.SqlClient.SqlAuthenticationMethod.ActiveDirectoryInteractive
|| authenticationMethod == System.Data.SqlClient.SqlAuthenticationMethod.ActiveDirectoryPassword;
}
}
}
FilesBasedAdalV3TokenCache
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.IO;
using System.Security.Cryptography;
namespace SQLAzureConnectivity
{
// This is a simple persistent cache implementation for an ADAL V3 desktop application
public class FilesBasedAdalV3TokenCache : TokenCache
{
public string CacheFilePath { get; }
private static readonly object FileLock = new object();
// Initializes the cache against a local file.
// If the file is already present, it loads its content in the ADAL cache
public FilesBasedAdalV3TokenCache(string filePath)
{
CacheFilePath = filePath;
this.AfterAccess = AfterAccessNotification;
this.BeforeAccess = BeforeAccessNotification;
lock (FileLock)
{
this.DeserializeAdalV3(ReadFromFileIfExists(CacheFilePath));
}
}
// Empties the persistent store.
public override void Clear()
{
base.Clear();
File.Delete(CacheFilePath);
}
// Triggered right before ADAL needs to access the cache.
// Reload the cache from the persistent store in case it changed since the last access.
void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
lock (FileLock)
{
this.DeserializeAdalV3(ReadFromFileIfExists(CacheFilePath));
}
}
// Triggered right after ADAL accessed the cache.
void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if the access operation resulted in a cache update
if (this.HasStateChanged)
{
lock (FileLock)
{
// reflect changes in the persistent store
WriteToFileIfNotNull(CacheFilePath, this.SerializeAdalV3());
// once the write operation took place, restore the HasStateChanged bit to false
this.HasStateChanged = false;
}
}
}
/// <summary>
/// Read the content of a file if it exists
/// </summary>
/// <param name="path">File path</param>
/// <returns>Content of the file (in bytes)</returns>
private byte[] ReadFromFileIfExists(string path)
{
byte[] protectedBytes = (!string.IsNullOrEmpty(path) && File.Exists(path))
? File.ReadAllBytes(path) : null;
byte[] unprotectedBytes = (protectedBytes != null)
? ProtectedData.Unprotect(protectedBytes, null, DataProtectionScope.CurrentUser) : null;
return unprotectedBytes;
}
/// <summary>
/// Writes a blob of bytes to a file. If the blob is <c>null</c>, deletes the file
/// </summary>
/// <param name="path">path to the file to write</param>
/// <param name="blob">Blob of bytes to write</param>
private static void WriteToFileIfNotNull(string path, byte[] blob)
{
if (blob != null)
{
byte[] protectedBytes = ProtectedData.Protect(blob, null, DataProtectionScope.CurrentUser);
File.WriteAllBytes(path, protectedBytes);
}
else
{
File.Delete(path);
}
}
}
}
Then before using a SQLConnection write these two lines:
var provider = new ActiveDirectoryAuthProvider("ClientID from the Azure app you set up earlier");
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, provider);
References:
https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/Token-cache-serialization
https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/Acquiring-tokens-interactively---Public-client-application-flows#properties-or-platformparameters-constructors-parameters-common-to-most-platforms
https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/AcquireTokenSilentAsync-using-a-cached-token#recommended-pattern-to-acquire-a-token
https://learn.microsoft.com/en-us/azure/sql-database/active-directory-interactive-connect-azure-sql-db
As mentioned elsewhere, you can use ODBC to connect, without registering your app in the Azure Portal. The interactive prompt will be shown whenever a new connection is added to the pool. Thus, even if you open multiple ODBC connections using the same connection string, you will only see the prompt once within your application lifecycle (or until the connection pool is recycled).
If you don't want to use ODBC, you may also use OLE DB with the MSOLEDBSQL driver, which has similar (or better) performance than the native SQL Client provider (which is deprecated and shouldn't be used anyway):
using System.Data.OleDb;
...
OleDbConnection con = new OleDbConnection("Provider=MSOLEDBSQL;Data Source=sqlserver.database.windows.net;User ID=user#domain.com;Initial Catalog=database;Authentication=ActiveDirectoryInteractive");
This may not be the best place to put this answer, as is it is specific to unit testing sql server and visual studio (community,prof,ent) -- https://youtu.be/OZiTKfNSXh4 # 1:10 -- via mfa interactive using #Dan answer.
The problem is that generating a c#/sql unit test project can be done using interactive connection. But running any unit test will fail because mfa interactive is not supported by SqlClient provider. Below is a work-around.
New file OleDatabaseTestService.cs
using Microsoft.Data.Tools.Schema.Sql.UnitTesting;
using System.Data.OleDb;
namespace [YourNamespace]Tests
{
public class OleDatabaseTestService : SqlDatabaseTestService
{
static OleDatabaseTestService()
{
SetupConext();
}
private static ConnectionContext _contextExecution = null;
private static ConnectionContext _contextPrivileged = null;
public static ConnectionContext ContextExecution { get; set; } = null;
public static ConnectionContext ContextPrivileged { get; set; } = null;
public override ConnectionContext OpenExecutionContext()
{
return ContextExecution;
}
public override ConnectionContext OpenPrivilegedContext()
{
return ContextPrivileged == null ? ContextExecution : ContextPrivileged;
}
// TODO: This can be a written a lot better - please edit this SO if you wish to help
protected static ConnectionContext SetupConext()
{
var context = new ConnectionContext();
context.Provider = OleDbFactory.Instance;
var connection = context.Provider.CreateConnection();
// TODO: Drive the connection string from app.config interactive connection string (wizard creates interactive correctly, but not supported by SqlClient provider)
// var connectionSection = (SqlUnitTestingSection)ConfigurationManager.GetSection("SqlUnitTesting"); // DbConnection connection = new OleDbConnection(
connection.ConnectionString = "Provider=MSOLEDBSQL;Data Source=[azure_database_name].database.windows.net;Initial Catalog=[initial db];User ID=[email];Authentication=ActiveDirectoryInteractive"; // + connectionSection.ExecutionContext.ConnectionString;
connection.Open();
context.Connection = connection;
ContextExecution = context;
ContextPrivileged = context;
return context;
}
}
}
Change to SqlDatabaseSetup.cs
using Microsoft.Data.Tools.Schema.Sql.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace [YourNamespace]Tests
{
[TestClass()]
public class SqlDatabaseSetup
{
[AssemblyInitialize()]
public static void InitializeAssembly(TestContext ctx)
{
var service = new OleDatabaseTestService();
SqlDatabaseTestClass.TestService = service;
SqlDatabaseTestClass.TestService.DeployDatabaseProject();
SqlDatabaseTestClass.TestService.GenerateData();
}
}
}
Please add a comment on where this would best be moved to. Or if
someone prefers this as a Question/self-Answered on its own (no need
to waste points).
I write a small program to send fax using FAXCOMLIB .
I make a class "fax" ,here is the code :
internal class Fax
{
public void SendFax( string FileName, string FaxNumber)
{
if (FaxNumber != "")
{
try
{
FAXCOMLib.FaxServer faxServer = new FAXCOMLib.FaxServerClass();
faxServer.Connect(Environment.MachineName);
FAXCOMLib.FaxDoc faxDoc = (FAXCOMLib.FaxDoc)faxServer.CreateDocument(FileName);
faxDoc.RecipientName = "گیرنده";
faxDoc.FaxNumber = FaxNumber;
faxDoc.DisplayName = "Asa";
int Response = faxDoc.Send();
faxServer.Disconnect();
}
catch (Exception Ex) { MessageBox.Show(Ex.Message); }
}
}
}
So when i want to execute the code i got these errors:
1-Error 13 Interop type 'FAXCOMLib.FaxServerClass' cannot be embedded. Use the applicable interface instead
2-Error 12 The type 'FAXCOMLib.FaxServerClass' has no constructors defined
in your project references, expand it and select the assembly in question (whatever the name is... FAX... whatever), then right click on it and go to properties. In there you will see the "Embed Interop Type" property - change it to "False"
I have a class that I wrote that saves and retrieves any objects to a windows phone isolated storage system. Have a look...
public class DataCache
{
// Method to store an object to phone ************************************
public void StoreToPhone(string key, Object objectToStore)
{
var settings = IsolatedStorageSettings.ApplicationSettings;
try
{
if (existsInStorage(key))
{
settings.Remove(key);
settings.Add(key, objectToStore);
}
else
{
settings.Add(key, objectToStore);
}
}
catch (Exception e)
{
MessageBox.Show("An error occured while trying to cache data: " + e.Message);
}
}
// Method to retrieve an object ******************************************
public Object retrieveFromPhone(string key)
{
var settings = IsolatedStorageSettings.ApplicationSettings;
Object retrievedObject = null;
try
{
if (existsInStorage(key))
{
settings.TryGetValue<Object>(key, out retrievedObject);
}
else
{
MessageBox.Show(string.Format("Cannot find key {0} in isolated storage", key));
}
}
catch(Exception e)
{
MessageBox.Show("An error occured while trying to retrieve cache object: "+e.Message);
}
return retrievedObject;
}
// Helper method to check if there is space on the phone to cache the data
private bool IsSpaceAvailable(long spaceReq)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
long spaceAvail = store.AvailableFreeSpace;
if (spaceReq > spaceAvail)
{
return false;
}
return true;
}
}
// Method to check if key exists in isolated storage *********************
public bool existsInStorage(string key)
{
var settings = IsolatedStorageSettings.ApplicationSettings;
bool objectExistsInStorage = settings.Contains(key);
return objectExistsInStorage;
}
}
When I run my app and try and store some data using my StoreToPhone() method I get the following error:
An error occurred while trying to cache data: Value does not fall within the expected range
I don't exactly know what this means.. Is it not expecting this type of object? I'm not sure... I'm passing it a custom class I wrote fyi.
Some times before I too ran into same problem.
It seems the error says 'there may be duplicate value in the storage'.
so i used 'remove' before 'add', and then also i found not everything was saved, so i used 'save' function after 'add'.
It worked for me...
IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;
appSettings.Remove("name");
appSettings.Add("name", "James Carter");
appSettings.Save();
tbResults.Text = (string)appSettings["name"];
Is it possible to read the publisher name of the currently running ClickOnce application (the one you set at Project Properties -> Publish -> Options -> Publisher name in Visual Studio)?
The reason why I need it is to run another instance of the currently running application as described in this article and pass parameters to it.
Of course I do know my application's publisher name, but if I hard code it and later on I decide to change my publisher's name I will most likely forget to update this piece of code.
Here is another option. Note that it will only get the publisher name for the currently running application, which is all I need.
I'm not sure if this is the safest way to parse the XML.
public static string GetPublisher()
{
XDocument xDocument;
using (MemoryStream memoryStream = new MemoryStream(AppDomain.CurrentDomain.ActivationContext.DeploymentManifestBytes))
using (XmlTextReader xmlTextReader = new XmlTextReader(memoryStream))
{
xDocument = XDocument.Load(xmlTextReader);
}
var description = xDocument.Root.Elements().Where(e => e.Name.LocalName == "description").First();
var publisher = description.Attributes().Where(a => a.Name.LocalName == "publisher").First();
return publisher.Value;
}
You would think this would be trivial, but I don't see anything in the framework that gives you this info.
If you want a hack, you can get the publisher from the registry.
Disclaimer - Code is ugly and untested...
...
var publisher = GetPublisher("My App Name");
...
public static string GetPublisher(string application)
{
using (var key = Registry.CurrentUser.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Uninstall"))
{
var appKey = key.GetSubKeyNames().FirstOrDefault(x => GetValue(key, x, "DisplayName") == application);
if (appKey == null) { return null; }
return GetValue(key, appKey, "Publisher");
}
}
private static string GetValue(RegistryKey key, string app, string value)
{
using (var subKey = key.OpenSubKey(app))
{
if (!subKey.GetValueNames().Contains(value)) { return null; }
return subKey.GetValue(value).ToString();
}
}
If you find a better solution, please follow-up.
I dont know about ClickOnce, but normally, you can read the assembly-info using the System.Reflection framework:
public string AssemblyCompany
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCompanyAttribute)attributes[0]).Company;
}
}
Unfortunately, theres no "publisher" custom-attribute, just throwing this out as a possible work-around
i am using the arcGIS api to make a plugin for arcFM, when i try to run this code
Type t = Type.GetTypeFromProgID("esriFramework.AppRef");
System.Object obj = Activator.CreateInstance(t);
pApp = obj as IApplication;
i get
System.Runtime.InteropServices.COMException(0x8000FFFF): Creating an instance of the component with CLSID {Appref CLSID HERE} from the IClassFactory faileddue to the following error: 8000ffff
Thanks
This was impossible i needed to be using arcMap not ArcFM
In the AppRef CoClass documentation, it says:
Note you can only use the AppRef
object if your code is running inside
one of the ArcGIS application
processes.
Forum posts seem to confirm that this is the same error which is seen when this constraint has been violated:
From http://forums.esri.com/Thread.asp?c=93&f=1729&t=217861:
It is my understanding that there is
indeed no way to access the
IApplication instance from a
geoprocessing script.
In theory, if your task is purely
geoprocessing, you should be able to
do it all without accessing the
IApplication object.
It looks like the OP of the above forum post was able to get around their problem by "using IToolboxWorkspace and accessing directely the Esri-toolboxes". This was her code:
public IGPTool GetTool(string _sToolName, string _sToolboxName)
{
IWorkspaceFactory pGPTFact;
IToolboxWorkspace pToolboxWorkspace;
IGPToolbox pGPToolbox;
IGPTool pGPTool;
pGPTFact = new ToolboxWorkspaceFactoryClass();
pToolboxWorkspace = pGPTFact.OpenFromFile(
ArcGISInstallFolder + #"\ArcToolbox\Toolboxes", 0) as IToolboxWorkspace;
pGPToolbox = pToolboxWorkspace.OpenToolbox(_sToolboxName);
pGPTool = pGPToolbox.OpenTool(_sToolName);
return pGPTool;
}
private string ArcGISInstallFolder
{
get
{
if (string.IsNullOrEmpty(this.m_sArcGISInstallFolder))
{
Microsoft.Win32.RegistryKey regkey;
regkey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
#"Software\ESRI\ArcGIS", false);
this.m_sArcGISInstallFolder = regkey.GetValue("InstallDir") as String;
}
return this.m_sArcGISInstallFolder;
}
}
Perhaps you can accomplish your goal either without the AppRef object or by running your script from inside the application.