Skip to content

Commit f5d6493

Browse files
committed
Improved diagnostic and implemented connection connection to external and live dasets.
1 parent a9859f0 commit f5d6493

9 files changed

Lines changed: 211 additions & 29 deletions

File tree

AnalyzeInExcel/AnalyzeInExcel.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,14 @@
122122
<DependentUpon>App.xaml</DependentUpon>
123123
<SubType>Code</SubType>
124124
</Compile>
125+
<Compile Include="ExcelHelper.cs" />
125126
<Compile Include="MainWindow.xaml.cs">
126127
<DependentUpon>MainWindow.xaml</DependentUpon>
127128
<SubType>Code</SubType>
128129
</Compile>
129130
</ItemGroup>
130131
<ItemGroup>
132+
<Compile Include="ModelHelper.cs" />
131133
<Compile Include="OdcHelper.cs" />
132134
<Compile Include="Options.cs" />
133135
<Compile Include="Properties\AssemblyInfo.cs">

AnalyzeInExcel/App.xaml.cs

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Windows;
66
using System.Diagnostics;
77
using AutoUpdaterDotNET;
8+
using System.Windows.Input;
89

910
namespace AnalyzeInExcel
1011
{
@@ -26,11 +27,33 @@ public void CheckUpdates(bool synchronous = true)
2627
AutoUpdater.Start($@"https://cdn.sqlbi.com/updates/AnalyzeInExcelAutoUpdater.xml?random={new Random().Next()}");
2728
}
2829

30+
/// <summary>
31+
/// THe user requested an options window instead of running the default action
32+
/// </summary>
33+
public bool OptionsRequested { get; private set; }
34+
35+
/// <summary>
36+
/// Check conditions to open Options window instead of directly opening Excel
37+
/// </summary>
38+
protected void InitializeOptionRequested()
39+
{
40+
// Pressing CTRL (left or right) when the external tool is launched activates the option window
41+
OptionsRequested = System.Windows.Input.Keyboard.IsKeyDown(Key.LeftCtrl) || System.Windows.Input.Keyboard.IsKeyDown(Key.LeftCtrl);
42+
}
43+
44+
public MessageBoxResult ShowMessage( string message )
45+
{
46+
return MessageBox.Show(message, "Analyze in Excel for Power BI Desktop");
47+
}
48+
2949
protected override void OnStartup(StartupEventArgs e)
3050
{
51+
// Store request to access options
52+
InitializeOptionRequested();
53+
3154
// Read configuration
3255
var result = Parser.Default.ParseArguments<Options>(e.Args)
33-
.WithNotParsed(errors => MessageBox.Show("Invalid configuration, check the pbitool.json file\n" + String.Join(";", from err in errors select err.ToString())))
56+
.WithNotParsed(errors => ShowMessage("Invalid configuration, check the pbitool.json file\n" + String.Join(";", from err in errors select err.ToString())))
3457
.WithParsed(options => AppOptions = options);
3558

3659
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration configuration = Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.CreateDefault();
@@ -40,23 +63,49 @@ protected override void OnStartup(StartupEventArgs e)
4063

4164
string serverName = ((App)Application.Current).AppOptions?.Server;
4265
string databaseName = ((App)Application.Current).AppOptions?.Database;
43-
string cubeName = "Model"; // TODO get this from the model?
66+
string cubeName = ModelHelper.GetModelName(serverName, databaseName);
4467
if (serverName != null && databaseName != null)
4568
{
4669
try
4770
{
48-
// Create ODC file
49-
OdcHelper.CreateOdcFile(serverName, databaseName, cubeName);
50-
var fileName = OdcHelper.OdcFilePath();
71+
if (serverName.StartsWith("XXXpbiazure"))
72+
{
73+
ShowMessage("Power BI is connected to an external dataset on Power BI. You must connect Excel to the external dataset.");
74+
tc.TrackEvent("External Power BI Dataset");
75+
}
76+
else if (string.IsNullOrEmpty(cubeName))
77+
{
78+
ShowMessage("Power BI has an empty model or it is connected to an external dataset. You must connect Excel to the external dataset.");
79+
tc.TrackEvent("Model not available");
80+
}
81+
else if (ExcelHelper.IsExcelAvailable())
82+
{
83+
// TODO: Manage options requested
84+
if (OptionsRequested)
85+
{
86+
// TODO request action / configuration to users
87+
}
88+
89+
// Create ODC file
90+
OdcHelper.CreateOdcFile(serverName, databaseName, cubeName);
91+
var fileName = OdcHelper.OdcFilePath();
5192

52-
// Open ODC file
53-
var p = new Process();
54-
p.StartInfo = new ProcessStartInfo(fileName)
93+
// Open ODC file
94+
var p = new Process
95+
{
96+
StartInfo = new ProcessStartInfo(fileName)
97+
{
98+
UseShellExecute = true
99+
}
100+
};
101+
tc.TrackEvent("Run Excel");
102+
p.Start();
103+
}
104+
else
55105
{
56-
UseShellExecute = true
57-
};
58-
tc.TrackEvent("Run Excel");
59-
p.Start();
106+
ShowMessage("Excel is not available. Please check whether Excel is correctly installed.");
107+
tc.TrackEvent("Excel not available");
108+
}
60109
tc.Flush();
61110
// Check updates synchronously when Excel starts, no wait for Excel
62111
CheckUpdates(true);
@@ -66,7 +115,7 @@ protected override void OnStartup(StartupEventArgs e)
66115
{
67116
tc.TrackException(ex);
68117
tc.Flush();
69-
MessageBox.Show("Error launching Excel: " + ex.Message);
118+
ShowMessage("Error launching Excel: " + ex.Message);
70119
}
71120
}
72121
else

AnalyzeInExcel/ExcelHelper.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
namespace AnalyzeInExcel
4+
{
5+
public class ExcelHelper
6+
{
7+
/// <summary>
8+
/// Check whether Excel is installed
9+
/// </summary>
10+
/// <returns>true if Excel is installed</returns>
11+
public static bool IsExcelAvailable()
12+
{
13+
var type = Type.GetTypeFromProgID("Excel.Application");
14+
return (type != null);
15+
}
16+
}
17+
}

AnalyzeInExcel/ModelHelper.cs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data.OleDb;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace AnalyzeInExcel
9+
{
10+
public class ModelHelper
11+
{
12+
internal enum AsInstanceType
13+
{
14+
Other,
15+
AsAzure,
16+
PbiDedicated,
17+
PbiPremium,
18+
PbiDataset
19+
}
20+
21+
private static bool IsProtocolSchemeInstance(string dataSourceUri, string protocolScheme)
22+
{
23+
return dataSourceUri?.StartsWith(protocolScheme, StringComparison.InvariantCultureIgnoreCase) ?? false;
24+
}
25+
internal static AsInstanceType GetAsInstanceType(string dataSourceUri)
26+
{
27+
if (IsProtocolSchemeInstance(dataSourceUri, "asazure://"))
28+
{
29+
return AsInstanceType.AsAzure;
30+
}
31+
if (IsProtocolSchemeInstance(dataSourceUri, "pbidedicated://"))
32+
{
33+
return AsInstanceType.PbiDedicated;
34+
}
35+
if (IsProtocolSchemeInstance(dataSourceUri, "powerbi://"))
36+
{
37+
return AsInstanceType.PbiPremium;
38+
}
39+
if (IsProtocolSchemeInstance(dataSourceUri, "pbiazure://"))
40+
{
41+
return AsInstanceType.PbiDataset;
42+
}
43+
return AsInstanceType.Other;
44+
}
45+
46+
/// <summary>
47+
/// Returns the OLE DB connection string based on serverName and databaseName
48+
/// </summary>
49+
/// <param name="serverName"></param>
50+
/// <param name="databaseName"></param>
51+
/// <returns>Connection string for OLE DB</returns>
52+
public static string GetOleDbConnectionString( string serverName, string databaseName )
53+
{
54+
// Choose the proper connection string
55+
string connectionString;
56+
switch (GetAsInstanceType(serverName))
57+
{
58+
case AsInstanceType.PbiDataset: // Integrated Security=ClaimsToken;
59+
connectionString = $"Provider=MSOLAP;Persist Security Info=True;Initial Catalog=sobe_wowvirtualserver-{databaseName};Data Source={serverName};MDX Compatibility=1;Safety Options=2;MDX Missing Member Mode=Error;Identity Provider=https://login.microsoftonline.com/common, https://analysis.windows.net/powerbi/api, 929d0ec0-7a41-4b1e-bc7c-b754a28bddcc;Update Isolation Level=2";
60+
break;
61+
case AsInstanceType.PbiDedicated:
62+
case AsInstanceType.PbiPremium:
63+
case AsInstanceType.AsAzure:
64+
connectionString = $"Provider=MSOLAP;Persist Security Info=True;Data Source={serverName};Update Isolation Level=2;Initial Catalog={databaseName}";
65+
break;
66+
case AsInstanceType.Other:
67+
default:
68+
connectionString = $"Provider=MSOLAP;Integrated Security=SSPI;Persist Security Info=True;Data Source={serverName};Update Isolation Level=2;Initial Catalog={databaseName}";
69+
break;
70+
}
71+
return connectionString;
72+
}
73+
74+
/// <summary>
75+
/// Check whether the connection has a data model
76+
/// </summary>
77+
/// <param name="serverName">Server name</param>
78+
/// <param name="databaseName">Database name</param>
79+
/// <returns>true it the connection has a data model</returns>
80+
public static string GetModelName(string serverName, string databaseName)
81+
{
82+
string result = null;
83+
string connectionString = GetOleDbConnectionString(serverName, databaseName);
84+
using (OleDbConnection connection = new OleDbConnection(connectionString))
85+
{
86+
try
87+
{
88+
using (OleDbCommand command = new OleDbCommand("select CUBE_NAME from $SYSTEM.MDSCHEMA_CUBES", connection))
89+
{
90+
connection.Open();
91+
using (OleDbDataReader reader = command.ExecuteReader())
92+
{
93+
if (reader.Read())
94+
{
95+
result = reader.GetString(0);
96+
}
97+
reader.Close();
98+
}
99+
}
100+
}
101+
catch (System.Data.Common.DbException)
102+
{
103+
// Ignore DB Exception and return a null model name
104+
}
105+
}
106+
return result;
107+
}
108+
}
109+
}

AnalyzeInExcel/OdcHelper.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public static class OdcHelper
77
{
88
public static void CreateOdcFile(string datasource, string database, string cube)
99
{
10+
string oledbConnectionString = ModelHelper.GetOleDbConnectionString(datasource, database);
1011
string odcHeader = @"
1112
<html xmlns:o=""urn:schemas-microsoft-com:office:office""
1213
xmlns=""http://www.w3.org/TR/REC-html40"">
@@ -28,9 +29,9 @@ public static void CreateOdcFile(string datasource, string database, string cube
2829
xmlns:odc=""urn:schemas-microsoft-com:office:odc""
2930
xmlns=""http://www.w3.org/TR/REC-html40"">
3031
<odc:Connection odc:Type=""OLEDB"">
31-
<odc:ConnectionString>Provider=MSOLAP;Integrated Security=SSPI;Persist Security Info=True;Data Source={0};Update Isolation Level=2;Initial Catalog={1}</odc:ConnectionString>
32+
<odc:ConnectionString>{0}</odc:ConnectionString>
3233
<odc:CommandType>Cube</odc:CommandType>
33-
<odc:CommandText>{2}</odc:CommandText>
34+
<odc:CommandText>{1}</odc:CommandText>
3435
</odc:Connection>
3536
</odc:OfficeDataConnection>
3637
</xml>";
@@ -120,7 +121,7 @@ function init() {
120121
";
121122

122123
var odcPath = OdcFilePath();
123-
File.WriteAllText(odcPath, odcHeader + string.Format(odcBody, datasource, database, cube) + odcFooter);
124+
File.WriteAllText(odcPath, odcHeader + string.Format(odcBody, oledbConnectionString, cube) + odcFooter);
124125

125126
}
126127

AnalyzeInExcel/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,5 @@
5151
// You can specify all the values or you can default the Build and Revision Numbers
5252
// by using the '*' as shown below:
5353
// [assembly: AssemblyVersion("1.0.*")]
54-
[assembly: AssemblyVersion("1.0.0.0")]
55-
[assembly: AssemblyFileVersion("1.0.0.0")]
54+
[assembly: AssemblyVersion("1.0.1.0")]
55+
[assembly: AssemblyFileVersion("1.0.1.0")]

ExternalToolsInstaller/ExternalToolsInstaller.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,10 @@ private TelemetryClient GetTelemetryClient( bool telemetryEnabled )
111111
private void ExternalToolsInstaller_AfterInstall(object sender, InstallEventArgs e)
112112
{
113113
bool telemetryEnabled = IsSetupTelemetryEnabled();
114-
var ev = new EventTelemetry();
115-
ev.Name = "Install";
114+
var ev = new EventTelemetry
115+
{
116+
Name = "Install"
117+
};
116118

117119
// Fix version installed
118120
ExternalToolConfiguration externalToolConfiguration = ReadExternalToolConfiguration();
@@ -174,8 +176,10 @@ private void ExternalToolsInstaller_AfterUninstall(object sender, InstallEventAr
174176

175177
// Enable telemetry if it was enabled in configuration file or if there is no configuration
176178
bool telemetryEnabled = externalToolConfiguration?.arguments?.Contains(TELEMETRY_ARGUMENT) ?? true;
177-
var ev = new EventTelemetry();
178-
ev.Name = "Uninstall";
179+
var ev = new EventTelemetry
180+
{
181+
Name = "Uninstall"
182+
};
179183
ev.Properties["Version"] = versionInstalled;
180184

181185
// Initialize Telemetry

ExternalToolsInstaller/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("1.0.0.0")]
36-
[assembly: AssemblyFileVersion("1.0.0.0")]
35+
[assembly: AssemblyVersion("1.0.1.0")]
36+
[assembly: AssemblyFileVersion("1.0.1.0")]

SetupAnalyzeInExcel/SetupAnalyzeInExcel.vdproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3420,15 +3420,15 @@
34203420
{
34213421
"Name" = "8:Microsoft Visual Studio"
34223422
"ProductName" = "8:Analyze in Excel for Power BI Desktop"
3423-
"ProductCode" = "8:{EF8F8D3C-B20D-4F5D-8CC4-9136EFE2F156}"
3424-
"PackageCode" = "8:{288320B6-9C1F-48DD-A698-D8D2AEDD5D22}"
3423+
"ProductCode" = "8:{BB602700-1871-4E9B-9006-D5C8DB14B3C7}"
3424+
"PackageCode" = "8:{B3E70D1B-D2B5-4592-AF7F-B003F750D83F}"
34253425
"UpgradeCode" = "8:{FC2F9C00-CAD5-455E-BD9D-B1C607F4ABDA}"
34263426
"AspNetVersion" = "8:4.0.30319.0"
34273427
"RestartWWWService" = "11:FALSE"
34283428
"RemovePreviousVersions" = "11:TRUE"
34293429
"DetectNewerInstalledVersion" = "11:TRUE"
34303430
"InstallAllUsers" = "11:TRUE"
3431-
"ProductVersion" = "8:1.0.0"
3431+
"ProductVersion" = "8:1.0.1"
34323432
"Manufacturer" = "8:Sqlbi"
34333433
"ARPHELPTELEPHONE" = "8:"
34343434
"ARPHELPLINK" = "8:"
@@ -4116,7 +4116,7 @@
41164116
{
41174117
"{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_B8059F38185844FF9E7100633B552E00"
41184118
{
4119-
"SourcePath" = "8:..\\AnalyzeInExcel\\obj\\Debug\\AnalyzeInExcel.exe"
4119+
"SourcePath" = "8:"
41204120
"TargetName" = "8:"
41214121
"Tag" = "8:"
41224122
"Folder" = "8:_3C819D033B8E4ED29DA3C4B4E2E7B98C"
@@ -4144,7 +4144,7 @@
41444144
}
41454145
"{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_BE740B1BEB9D410F82DDE5AF811E1E7C"
41464146
{
4147-
"SourcePath" = "8:..\\ExternalToolsInstaller\\obj\\Debug\\ExternalToolsInstaller.dll"
4147+
"SourcePath" = "8:"
41484148
"TargetName" = "8:"
41494149
"Tag" = "8:"
41504150
"Folder" = "8:_3C819D033B8E4ED29DA3C4B4E2E7B98C"

0 commit comments

Comments
 (0)