Skip to content

Commit

Permalink
Improve error message handling (#497)
Browse files Browse the repository at this point in the history
- Add special handling for token expired errors so they send with a clear flag that'll allow clients to take action on this case
- Send error message instead of callstack for all messages, and ensure all resource manager paths send back inner exceptions so users can understand the true root cause.
  • Loading branch information
kevcunnane authored Oct 14, 2017
1 parent b416951 commit 0c7f559
Show file tree
Hide file tree
Showing 17 changed files with 378 additions and 272 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Runtime.Serialization;

namespace Microsoft.SqlTools.ResourceProvider.Core
{
/// <summary>
/// The exception is used if any operation fails as a request failed due to an expired token
/// </summary>
public class ExpiredTokenException : ServiceExceptionBase
{
/// <summary>
/// Initializes a new instance of the ServiceFailedException class.
/// </summary>
public ExpiredTokenException()
{
}

/// <summary>
/// Initializes a new instance of the ServiceFailedException class with a specified error message.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception. </param>
public ExpiredTokenException(string message)
: base(message)
{
}

/// <summary>
/// Initializes a new instance of the ServiceFailedException class with a specified error message
/// and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception. </param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified</param>
public ExpiredTokenException(string message, Exception innerException)
: base(message, innerException)
{
}

/// <summary>
/// Initializes a new instance of the ServiceFailedException class with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
public ExpiredTokenException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ public class CreateFirewallRuleParams

}

public class CreateFirewallRuleResponse
public class CreateFirewallRuleResponse : TokenReliantResponse
{
public bool Result { get; set; }
/// <summary>
/// An error message for why the request failed, if any
/// </summary>
public string ErrorMessage { get; set; }
}

Expand Down Expand Up @@ -97,6 +99,4 @@ public class HandleFirewallRuleResponse
/// </summary>
public string IpAddress { get; set; }
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using System.Collections.Generic;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;

namespace Microsoft.SqlTools.ResourceProvider.Core.Contracts
{
/// <summary>
/// Any response which relies on a token may indicated that the operation failed due to token being expired.
/// All operational response messages should inherit from this class in order to support a standard method for defining
/// this failure path
/// </summary>
public class TokenReliantResponse
{
/// <summary>
/// Did this succeed?
/// </summary>
public bool Result { get; set; }

/// <summary>
/// If this failed, was it due to a token expiring?
/// </summary>
public bool IsTokenExpiredFailure { get; set; }
}
}
100 changes: 50 additions & 50 deletions src/Microsoft.SqlTools.ResourceProvider.Core/Localization/sr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,136 +27,136 @@ public static CultureInfo Culture
Keys.Culture = value;
}
}



public static string NoSubscriptionsFound
{
get
{
return Keys.GetString(Keys.NoSubscriptionsFound);
}
}
}

public static string AzureServerNotFound
{
get
{
return Keys.GetString(Keys.AzureServerNotFound);
}
}
}

public static string AzureSubscriptionFailedErrorMessage
{
get
{
return Keys.GetString(Keys.AzureSubscriptionFailedErrorMessage);
}
}
}

public static string DatabaseDiscoveryFailedErrorMessage
{
get
{
return Keys.GetString(Keys.DatabaseDiscoveryFailedErrorMessage);
}
}
}

public static string FirewallRuleAccessForbidden
{
get
{
return Keys.GetString(Keys.FirewallRuleAccessForbidden);
}
}
}

public static string FirewallRuleCreationFailed
{
get
{
return Keys.GetString(Keys.FirewallRuleCreationFailed);
}
}
}

public static string FirewallRuleCreationFailedWithError
{
get
{
return Keys.GetString(Keys.FirewallRuleCreationFailedWithError);
}
}
}

public static string InvalidIpAddress
{
get
{
return Keys.GetString(Keys.InvalidIpAddress);
}
}
}

public static string InvalidServerTypeErrorMessage
{
get
{
return Keys.GetString(Keys.InvalidServerTypeErrorMessage);
}
}
}

public static string LoadingExportableFailedGeneralErrorMessage
{
get
{
return Keys.GetString(Keys.LoadingExportableFailedGeneralErrorMessage);
}
}
}

public static string FirewallRuleUnsupportedConnectionType
{
get
{
return Keys.GetString(Keys.FirewallRuleUnsupportedConnectionType);
}
}
}

[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Keys
{
static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.ResourceProvider.Core.Localization.SR", typeof(SR).GetTypeInfo().Assembly);

static CultureInfo _culture = null;


public const string NoSubscriptionsFound = "NoSubscriptionsFound";


public const string AzureServerNotFound = "AzureServerNotFound";


public const string AzureSubscriptionFailedErrorMessage = "AzureSubscriptionFailedErrorMessage";


public const string DatabaseDiscoveryFailedErrorMessage = "DatabaseDiscoveryFailedErrorMessage";


public const string FirewallRuleAccessForbidden = "FirewallRuleAccessForbidden";


public const string FirewallRuleCreationFailed = "FirewallRuleCreationFailed";


public const string FirewallRuleCreationFailedWithError = "FirewallRuleCreationFailedWithError";


public const string InvalidIpAddress = "InvalidIpAddress";


public const string InvalidServerTypeErrorMessage = "InvalidServerTypeErrorMessage";


public const string LoadingExportableFailedGeneralErrorMessage = "LoadingExportableFailedGeneralErrorMessage";


public const string FirewallRuleUnsupportedConnectionType = "FirewallRuleUnsupportedConnectionType";



public const string NoSubscriptionsFound = "NoSubscriptionsFound";


public const string AzureServerNotFound = "AzureServerNotFound";


public const string AzureSubscriptionFailedErrorMessage = "AzureSubscriptionFailedErrorMessage";


public const string DatabaseDiscoveryFailedErrorMessage = "DatabaseDiscoveryFailedErrorMessage";


public const string FirewallRuleAccessForbidden = "FirewallRuleAccessForbidden";


public const string FirewallRuleCreationFailed = "FirewallRuleCreationFailed";


public const string FirewallRuleCreationFailedWithError = "FirewallRuleCreationFailedWithError";


public const string InvalidIpAddress = "InvalidIpAddress";


public const string InvalidServerTypeErrorMessage = "InvalidServerTypeErrorMessage";


public const string LoadingExportableFailedGeneralErrorMessage = "LoadingExportableFailedGeneralErrorMessage";


public const string FirewallRuleUnsupportedConnectionType = "FirewallRuleUnsupportedConnectionType";


private Keys()
{ }
Expand All @@ -177,7 +177,7 @@ public static string GetString(string key)
{
return resourceManager.GetString(key, _culture);
}

}
}
}

}
}
}
26 changes: 13 additions & 13 deletions src/Microsoft.SqlTools.ResourceProvider.Core/Localization/sr.resx
Original file line number Diff line number Diff line change
Expand Up @@ -120,45 +120,45 @@
<data name="NoSubscriptionsFound" xml:space="preserve">
<value>No subscriptions were found for the currently logged in user account.</value>
<comment></comment>
</data>
</data>
<data name="AzureServerNotFound" xml:space="preserve">
<value>The server you specified {0} does not exist in any subscription in {1}. Either you have signed in with an incorrect account or your server was removed from subscription(s) in this account. Please check your account and try again.</value>
<comment></comment>
</data>
</data>
<data name="AzureSubscriptionFailedErrorMessage" xml:space="preserve">
<value>An error occurred while getting Azure subscriptions</value>
<value>An error occurred while getting Azure subscriptions: {0}</value>
<comment></comment>
</data>
</data>
<data name="DatabaseDiscoveryFailedErrorMessage" xml:space="preserve">
<value>An error occurred while getting databases from servers of type {0} from {1}</value>
<comment></comment>
</data>
</data>
<data name="FirewallRuleAccessForbidden" xml:space="preserve">
<value>{0} does not have permission to change the server firewall rule. Try again with a different account that is an Owner or Contributor of the Azure subscription or the server.</value>
<comment></comment>
</data>
</data>
<data name="FirewallRuleCreationFailed" xml:space="preserve">
<value>An error occurred while creating a new firewall rule.</value>
<comment></comment>
</data>
</data>
<data name="FirewallRuleCreationFailedWithError" xml:space="preserve">
<value>An error occurred while creating a new firewall rule: '{0}'</value>
<comment></comment>
</data>
</data>
<data name="InvalidIpAddress" xml:space="preserve">
<value>Invalid IP address</value>
<comment></comment>
</data>
</data>
<data name="InvalidServerTypeErrorMessage" xml:space="preserve">
<value>Server Type is invalid.</value>
<comment></comment>
</data>
</data>
<data name="LoadingExportableFailedGeneralErrorMessage" xml:space="preserve">
<value>A required dll cannot be loaded. Please repair your application.</value>
<comment></comment>
</data>
</data>
<data name="FirewallRuleUnsupportedConnectionType" xml:space="preserve">
<value>Cannot open a firewall rule for the specified connection type</value>
<comment></comment>
</data>
</root>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# Azure Core DLL
NoSubscriptionsFound = No subscriptions were found for the currently logged in user account.
AzureServerNotFound = The server you specified {0} does not exist in any subscription in {1}. Either you have signed in with an incorrect account or your server was removed from subscription(s) in this account. Please check your account and try again.
AzureSubscriptionFailedErrorMessage = An error occurred while getting Azure subscriptions
AzureSubscriptionFailedErrorMessage = An error occurred while getting Azure subscriptions: {0}
DatabaseDiscoveryFailedErrorMessage = An error occurred while getting databases from servers of type {0} from {1}
FirewallRuleAccessForbidden = {0} does not have permission to change the server firewall rule. Try again with a different account that is an Owner or Contributor of the Azure subscription or the server.
FirewallRuleCreationFailed = An error occurred while creating a new firewall rule.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<note></note>
</trans-unit>
<trans-unit id="AzureSubscriptionFailedErrorMessage">
<source>An error occurred while getting Azure subscriptions</source>
<source>An error occurred while getting Azure subscriptions: {0}</source>
<target state="new">An error occurred while getting Azure subscriptions</target>
<note></note>
</trans-unit>
Expand Down
Loading

0 comments on commit 0c7f559

Please sign in to comment.