Load performance using Neoload with Ranorex - c#

I'm trying to use NeoLoad for performance with Ranorex and here is my code i have a Ranorex code and Neoload code that calls Ranorex code to be executed. When I run the second code I get this error:
No scenario name available. Please set a valid NeoLoad scenario name. I need to run the second code to perform some application performance monitoring using Neoload package on Ranorex.
First Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing;
using System.Threading;
using WinForms = System.Windows.Forms;
using Ranorex;
using Ranorex.Core;
using Ranorex.Core.Testing;
using Ranorex.Core.Repository;
namespace NewOpe.NeoLoad.Modules
{
#pragma warning disable 0436 //(CS0436) The type 'type' in 'assembly' conflicts with the imported type 'type2' in 'assembly'. Using the type defined in 'assembly'.
/// <summary>
///The loadrecord recording.
/// </summary>
[TestModule("0f400fed-c562-4ef4-99fb-40ee81b4fa59", ModuleType.Recording, 1)]
public partial class loadrecord : ITestModule
{
/// <summary>
/// Holds an instance of the NewOpe.NewOpeRepository repository.
/// </summary>
public static NewOpe.NewOpeRepository repo = NewOpe.NewOpeRepository.Instance;
static loadrecord instance = new loadrecord();
/// <summary>
/// Constructs a new instance.
/// </summary>
public loadrecord()
{
}
/// <summary>
/// Gets a static instance of this recording.
/// </summary>
public static loadrecord Instance
{
get { return instance; }
}
#region Variables
#endregion
/// <summary>
/// Starts the replay of the static recording <see cref="Instance"/>.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("Ranorex", "8.0")]
public static void Start()
{
TestModuleRunner.Run(Instance);
}
/// <summary>
/// Performs the playback of actions in this recording.
/// </summary>
/// <remarks>You should not call this method directly, instead pass the module
/// instance to the <see cref="TestModuleRunner.Run(ITestModule)"/> method
/// that will in turn invoke this method.</remarks>
[System.CodeDom.Compiler.GeneratedCode("Ranorex", "8.0")]
void ITestModule.Run()
{
Mouse.DefaultMoveTime = 300;
Keyboard.DefaultKeyPressTime = 100;
Delay.SpeedFactor = 1.00;
Init();
Report.Log(ReportLevel.Info, "Application", "Run application 'C:\\Users\\Ahmed Abd El Nasser\\Desktop\\dist\\run.bat' with arguments '' in normal mode.", new RecordItemIndex(0));
Host.Local.RunApplication("C:\\Users\\Ahmed Abd El Nasser\\Desktop\\dist\\run.bat", "", "C:\\Users\\Ahmed Abd El Nasser\\Desktop\\dist", false);
Delay.Milliseconds(0);
Report.Log(ReportLevel.Info, "Delay", "Waiting for 1m.", new RecordItemIndex(1));
Delay.Duration(60000, false);
Report.Log(ReportLevel.Info, "Mouse", "Mouse Left Click item 'FormOsseoViewRelease2Sprint12.JLayeredPane1.CUsersAhmedAbdElNasserDesktopGha' at 49;12.", repo.FormOsseoViewRelease2Sprint12.JLayeredPane1.CUsersAhmedAbdElNasserDesktopGhaInfo, new RecordItemIndex(2));
repo.FormOsseoViewRelease2Sprint12.JLayeredPane1.CUsersAhmedAbdElNasserDesktopGha.Click("49;12");
Delay.Milliseconds(200);
Report.Log(ReportLevel.Info, "Mouse", "Mouse Left Click item 'FormOsseoViewRelease2Sprint12.JLayeredPane1.Both' at 10;13.", repo.FormOsseoViewRelease2Sprint12.JLayeredPane1.BothInfo, new RecordItemIndex(3));
repo.FormOsseoViewRelease2Sprint12.JLayeredPane1.Both.Click("10;13");
Delay.Milliseconds(200);
Second Code:
using System;
using System.Globalization;
using Ranorex.Core.Testing;
namespace Ranorex.NeoLoad
{
/// <summary>
/// Starts a NeoLoad test
/// </summary>
/// <remarks>
/// A NeoLoad test can only be started, when a connection to the runtime and data exchange API was
/// established prior.
/// </remarks>
[TestModule("1702CBFB-DA15-4C42-B6C4-6FCBA8DAE96F", ModuleType.UserCode, 1)]
public class StartNeoLoadTest : ITestModule
{
// For testing, make it mockable
internal static INeoloadApi api = NeoloadApi.Instance;
/// <summary>
/// Check interval for operations that can timeout in the format 'hh:mm:ss'.
/// This interval needs to be smaller than the timeout.
/// </summary>
[TestVariable("29B0EB4D-D82E-4DDA-8ABB-355734B346D2")]
public string Interval { get; set; }
/// <summary>
/// Timeout for the connect operation in the format 'hh:mm:ss'.
/// </summary>
[TestVariable("7E6AAB81-CA2F-4084-A2B2-C0B8792122A1")]
public string Timeout { get; set; }
/// <summary>
/// The name of the scenario. Use this info tho identify the collected data on the NeoLoad server system.
/// </summary>
[TestVariable("7242C624-2E81-447E-A148-533E4BB082BE")]
public string Scenario { get; set; }
public StartNeoLoadTest()
{
this.Interval = "00:00:10";
this.Timeout = "00:01:00";
}
void ITestModule.Run()
{
if (string.IsNullOrWhiteSpace(this.Scenario))
{
throw new InvalidOperationException("No scenario name available. Please set a valid NeoLoad scenario name.");
}
try
{
const string fmt = #"hh\:mm\:ss";
var timeout = TimeSpan.ParseExact(this.Timeout, fmt, CultureInfo.InvariantCulture);
var interval = TimeSpan.ParseExact(this.Interval, fmt, CultureInfo.InvariantCulture);
if (timeout < interval)
{
throw new ArgumentException(string.Format("The given timeout of '{0}' is smaller than the interval with a value of '{1}', but interval has to be smaller than timeout.",
timeout.ToString(fmt), interval.ToString(fmt)));
}
api.StartNeoLoadTest(this.Scenario, timeout, interval);
}
catch (FormatException ex)
{
throw new Exception("'Timeout' or 'Interval' was specified with invalid format. Please use the format 'hh:mm:ss' e.g. '00:01:10' for one minute and ten seconds." + ex);
}
}
}
}

I know it is a fairly old question but the Ranorex/Neoload integration is now managed by Neotys and the source code can be found here:
https://github.com/Neotys-Labs/Ranorex

Related

System.Text.Json - failing to deserialize a REST response

I'm trying to implement the following API Endpoint. Due to the fact, System.Text.Json is now preferred over Newtonsoft.Json, I decided to try it. The response clearly works, but the deserialization doesn't.
Response
https://pastebin.com/VhDw5Rsg (Pastebin because it exceeds the limits)
Issue
I pasted the response into an online converter and it used to work for a bit, but then it broke again once I put the comments.
How do I fix it? I would also like to throw an exception if it fails to deserialize it.
Snippet
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Ardalis.GuardClauses;
using RestSharp;
namespace QSGEngine.Web.Platforms.Binance;
/// <summary>
/// Binance REST API implementation.
/// </summary>
internal class BinanceRestApiClient : IDisposable
{
/// <summary>
/// The base point url.
/// </summary>
private const string BasePointUrl = "https://api.binance.com";
/// <summary>
/// The key header.
/// </summary>
private const string KeyHeader = "X-MBX-APIKEY";
/// <summary>
/// REST Client.
/// </summary>
private readonly IRestClient _restClient = new RestClient(BasePointUrl);
/// <summary>
/// Initializes a new instance of the <see cref="BinanceRestApiClient"/> class.
/// </summary>
/// <param name="apiKey">Binance API key.</param>
/// <param name="apiSecret">Binance Secret key.</param>
public BinanceRestApiClient(string apiKey, string apiSecret)
{
Guard.Against.NullOrWhiteSpace(apiKey, nameof(apiKey));
Guard.Against.NullOrWhiteSpace(apiSecret, nameof(apiSecret));
ApiKey = apiKey;
ApiSecret = apiSecret;
}
/// <summary>
/// The API key.
/// </summary>
public string ApiKey { get; }
/// <summary>
/// The secret key.
/// </summary>
public string ApiSecret { get; }
/// <summary>
/// Gets the total account cash balance for specified account type.
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public AccountInformation? GetBalances()
{
var queryString = $"timestamp={GetNonce()}";
var endpoint = $"/api/v3/account?{queryString}&signature={AuthenticationToken(queryString)}";
var request = new RestRequest(endpoint, Method.GET);
request.AddHeader(KeyHeader, ApiKey);
var response = ExecuteRestRequest(request);
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception($"{nameof(BinanceRestApiClient)}: request failed: [{(int)response.StatusCode}] {response.StatusDescription}, Content: {response.Content}, ErrorMessage: {response.ErrorMessage}");
}
var deserialize = JsonSerializer.Deserialize<AccountInformation>(response.Content);
return deserialize;
}
/// <summary>
/// If an IP address exceeds a certain number of requests per minute
/// HTTP 429 return code is used when breaking a request rate limit.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
private IRestResponse ExecuteRestRequest(IRestRequest request)
{
const int maxAttempts = 10;
var attempts = 0;
IRestResponse response;
do
{
// TODO: RateLimiter
//if (!_restRateLimiter.WaitToProceed(TimeSpan.Zero))
//{
// Log.Trace("Brokerage.OnMessage(): " + new BrokerageMessageEvent(BrokerageMessageType.Warning, "RateLimit",
// "The API request has been rate limited. To avoid this message, please reduce the frequency of API calls."));
// _restRateLimiter.WaitToProceed();
//}
response = _restClient.Execute(request);
// 429 status code: Too Many Requests
} while (++attempts < maxAttempts && (int)response.StatusCode == 429);
return response;
}
/// <summary>
/// Timestamp in milliseconds.
/// </summary>
/// <returns>The current timestamp in milliseconds.</returns>
private long GetNonce()
{
return DateTimeOffset.Now.ToUnixTimeMilliseconds();
}
/// <summary>
/// Creates a signature for signed endpoints.
/// </summary>
/// <param name="payload">The body of the request.</param>
/// <returns>A token representing the request params.</returns>
private string AuthenticationToken(string payload)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(ApiSecret));
var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
return BitConverter.ToString(computedHash).Replace("-", "").ToLowerInvariant();
}
/// <summary>
/// The standard dispose destructor.
/// </summary>
~BinanceRestApiClient() => Dispose(false);
/// <summary>
/// Returns true if it is already disposed.
/// </summary>
public bool IsDisposed { get; private set; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <param name="disposing">If this method is called by a user's code.</param>
private void Dispose(bool disposing)
{
if (IsDisposed) return;
if (disposing)
{
}
IsDisposed = true;
}
/// <summary>
/// Throw if disposed.
/// </summary>
/// <exception cref="ObjectDisposedException"></exception>
private void ThrowIfDisposed()
{
if (IsDisposed)
{
throw new ObjectDisposedException("BinanceRestClient has been disposed.");
}
}
}
namespace QSGEngine.Web.Platforms.Binance;
/// <summary>
/// Information about the account.
/// </summary>
public class AccountInformation
{
/// <summary>
/// Commission percentage to pay when making trades.
/// </summary>
public decimal MakerCommission { get; set; }
/// <summary>
/// Commission percentage to pay when taking trades.
/// </summary>
public decimal TakerCommission { get; set; }
/// <summary>
/// Commission percentage to buy when buying.
/// </summary>
public decimal BuyerCommission { get; set; }
/// <summary>
/// Commission percentage to buy when selling.
/// </summary>
public decimal SellerCommission { get; set; }
/// <summary>
/// Boolean indicating if this account can trade.
/// </summary>
public bool CanTrade { get; set; }
/// <summary>
/// Boolean indicating if this account can withdraw.
/// </summary>
public bool CanWithdraw { get; set; }
/// <summary>
/// Boolean indicating if this account can deposit.
/// </summary>
public bool CanDeposit { get; set; }
/// <summary>
/// The time of the update.
/// </summary>
//[JsonConverter(typeof(TimestampConverter))]
public long UpdateTime { get; set; }
/// <summary>
/// The type of the account.
/// </summary>
public string AccountType { get; set; }
/// <summary>
/// List of assets with their current balances.
/// </summary>
public IEnumerable<Balance> Balances { get; set; }
/// <summary>
/// Permission types.
/// </summary>
public IEnumerable<string> Permissions { get; set; }
}
/// <summary>
/// Information about an asset balance.
/// </summary>
public class Balance
{
/// <summary>
/// The asset this balance is for.
/// </summary>
public string Asset { get; set; }
/// <summary>
/// The amount that isn't locked in a trade.
/// </summary>
public decimal Free { get; set; }
/// <summary>
/// The amount that is currently locked in a trade.
/// </summary>
public decimal Locked { get; set; }
/// <summary>
/// The total balance of this asset (Free + Locked).
/// </summary>
public decimal Total => Free + Locked;
}
System.Text.Json is implemented quite different compared to Newtonsoft.Json. It is written to be first and foremost a very fast (de)serializer, and try to be allocation-free as much as possible.
However, it also comes with its own set of limitations, and one of those limitations is that out of the box it's a bit more rigid in what it supports.
Let's look at your JSON:
{"makerCommission":10,"takerCommission":10,"buyerCommission":0,
"sellerCommission":0,"canTrade":true,"canWithdraw":true,"canDeposit":true,
"updateTime":1636983729026,"accountType":"SPOT",
"balances":[{"asset":"BTC","free":"0.00000000","locked":"0.00000000"},
{"asset":"LTC","free":"0.00000000","locked":"0.00000000"},
(reformatted and cut for example purposes)
There's two issues here that needs to be resolved:
The properties in the JSON is written with a lowercase first letter. This will simply not match the properties in your .NET Types out of the box.
The values for free and locked are strings in the JSON but typed as decimal in your .NET types.
To fix these, your deserialization code needs to tell System.Text.Json how to deal with them, and this is how:
var options = new System.Text.Json.JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
And then you pass this object in through the deserialization method, like this:
… = JsonSerializer.Deserialize<AccountInformation>(response.Content, options);
This should properly deserialize this content into your objects.

How to Hide Payment Cash on Delivery when Pick-up in Store Nopcommerce

I use plugin Cash On Delivery in Nopcommerce. But I want to edit the code, that hide Cash on Delivery payment when customer choose Pick-up in store. In the code, I find HidePaymentMethod, but I dont know how return true, when customer chooser radio button pick-up in store.
I am using nopcommerce 4.2.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Nop.Core;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Plugin.Payments.CashOnDelivery.Controllers;
using Nop.Services.Configuration;
using Nop.Services.Localization;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Plugins;
namespace Nop.Plugin.Payments.CashOnDelivery
{
/// <summary>
/// CashOnDelivery payment processor
/// </summary>
public class CashOnDeliveryPaymentProcessor : BasePlugin, IPaymentMethod
{
#region Fields
private readonly CashOnDeliveryPaymentSettings _cashOnDeliveryPaymentSettings;
private readonly ILocalizationService _localizationService;
private readonly IPaymentService _paymentService;
private readonly ISettingService _settingService;
private readonly IShoppingCartService _shoppingCartService;
private readonly IWebHelper _webHelper;
#endregion
#region Ctor
public CashOnDeliveryPaymentProcessor(CashOnDeliveryPaymentSettings cashOnDeliveryPaymentSettings,
ILocalizationService localizationService,
IPaymentService paymentService,
ISettingService settingService,
IShoppingCartService shoppingCartService,
IWebHelper webHelper)
{
_cashOnDeliveryPaymentSettings = cashOnDeliveryPaymentSettings;
_localizationService = localizationService;
_paymentService = paymentService;
_settingService = settingService;
_shoppingCartService = shoppingCartService;
_webHelper = webHelper;
}
#endregion
#region Methods
/// <summary>
/// Process a payment
/// </summary>
/// <param name="processPaymentRequest">Payment info required for an order processing</param>
/// <returns>Process payment result</returns>
public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest)
{
var result = new ProcessPaymentResult { NewPaymentStatus = PaymentStatus.Pending };
return result;
}
/// <summary>
/// Post process payment (used by payment gateways that require redirecting to a third-party URL)
/// </summary>
/// <param name="postProcessPaymentRequest">Payment info required for an order processing</param>
public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest)
{
//nothing
}
/// <summary>
/// Returns a value indicating whether payment method should be hidden during checkout
/// </summary>
/// <param name="cart">Shoping cart</param>
/// <returns>true - hide; false - display.</returns>
public bool HidePaymentMethod(IList<ShoppingCartItem> cart)
{
//you can put any logic here
//for example, hide this payment method if all products in the cart are downloadable
//or hide this payment method if current customer is from certain country
return _cashOnDeliveryPaymentSettings.ShippableProductRequired && !_shoppingCartService.ShoppingCartRequiresShipping(cart);
}
/// <summary>
/// Gets additional handling fee
/// </summary>
/// <param name="cart">Shoping cart</param>
/// <returns>Additional handling fee</returns>
public decimal GetAdditionalHandlingFee(IList<ShoppingCartItem> cart)
{
var result = _paymentService.CalculateAdditionalFee(cart,
_cashOnDeliveryPaymentSettings.AdditionalFee, _cashOnDeliveryPaymentSettings.AdditionalFeePercentage);
return result;
}
/// <summary>
/// Captures payment
/// </summary>
/// <param name="capturePaymentRequest">Capture payment request</param>
/// <returns>Capture payment result</returns>
public CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest)
{
var result = new CapturePaymentResult();
result.AddError("Capture method not supported");
return result;
}
/// <summary>
/// Refunds a payment
/// </summary>
/// <param name="refundPaymentRequest">Request</param>
/// <returns>Result</returns>
public RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest)
{
var result = new RefundPaymentResult();
result.AddError("Refund method not supported");
return result;
}
/// <summary>
/// Voids a payment
/// </summary>
/// <param name="voidPaymentRequest">Request</param>
/// <returns>Result</returns>
public VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest)
{
var result = new VoidPaymentResult();
result.AddError("Void method not supported");
return result;
}
/// <summary>
/// Process recurring payment
/// </summary>
/// <param name="processPaymentRequest">Payment info required for an order processing</param>
/// <returns>Process payment result</returns>
public ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest)
{
var result = new ProcessPaymentResult();
result.AddError("Recurring payment not supported");
return result;
}
/// <summary>
/// Cancels a recurring payment
/// </summary>
/// <param name="cancelPaymentRequest">Request</param>
/// <returns>Result</returns>
public CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest)
{
var result = new CancelRecurringPaymentResult();
result.AddError("Recurring payment not supported");
return result;
}
/// <summary>
/// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods)
/// </summary>
/// <param name="order">Order</param>
/// <returns>Result</returns>
public bool CanRePostProcessPayment(Order order)
{
if (order == null)
throw new ArgumentNullException(nameof(order));
//it's not a redirection payment method. So we always return false
return false;
}
public IList<string> ValidatePaymentForm(IFormCollection form)
{
var warnings = new List<string>();
return warnings;
}
public ProcessPaymentRequest GetPaymentInfo(IFormCollection form)
{
var paymentInfo = new ProcessPaymentRequest();
return paymentInfo;
}
public override string GetConfigurationPageUrl()
{
return $"{_webHelper.GetStoreLocation()}Admin/PaymentCashOnDelivery/Configure";
}
public Type GetControllerType()
{
return typeof(PaymentCashOnDeliveryController);
}
public override void Install()
{
var settings = new CashOnDeliveryPaymentSettings
{
DescriptionText = "<p>In cases where an order is placed, an authorized representative will contact you, personally or over telephone, to confirm the order.<br />After the order is confirmed, it will be processed.<br />Orders once confirmed, cannot be cancelled.</p><p>P.S. You can edit this text from admin panel.</p>",
SkipPaymentInfo = false
};
_settingService.SaveSetting(settings);
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.DescriptionText", "Description");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.DescriptionText.Hint", "Enter info that will be shown to customers during checkout");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.AdditionalFee", "Additional fee");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.AdditionalFee.Hint", "The additional fee.");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.AdditionalFeePercentage", "Additional fee. Use percentage");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.AdditionalFeePercentage.Hint", "Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used.");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.ShippableProductRequired", "Shippable product required");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.ShippableProductRequired.Hint", "An option indicating whether shippable products are required in order to display this payment method during checkout.");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.PaymentMethodDescription", "Pay by \"Cash on delivery\"");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.SkipPaymentInfo", "Skip payment information page");
_localizationService.AddOrUpdatePluginLocaleResource("Plugins.Payment.CashOnDelivery.SkipPaymentInfo.Hint", "An option indicating whether we should display a payment information page for this plugin.");
base.Install();
}
public override void Uninstall()
{
//settings
_settingService.DeleteSetting<CashOnDeliveryPaymentSettings>();
//locales
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.DescriptionText");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.DescriptionText.Hint");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.AdditionalFee");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.AdditionalFee.Hint");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.AdditionalFeePercentage");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.AdditionalFeePercentage.Hint");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.ShippableProductRequired");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.ShippableProductRequired.Hint");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.PaymentMethodDescription");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.SkipPaymentInfo");
_localizationService.DeletePluginLocaleResource("Plugins.Payment.CashOnDelivery.SkipPaymentInfo.Hint");
base.Uninstall();
}
/// <summary>
/// Gets a name of a view component for displaying plugin in public store ("payment info" checkout step)
/// </summary>
/// <returns>View component name</returns>
public string GetPublicViewComponentName()
{
return "PaymentCashOnDelivery";
}
#endregion
#region Properies
/// <summary>
/// Gets a value indicating whether capture is supported
/// </summary>
public bool SupportCapture => false;
/// <summary>
/// Gets a value indicating whether partial refund is supported
/// </summary>
public bool SupportPartiallyRefund => false;
/// <summary>
/// Gets a value indicating whether refund is supported
/// </summary>
public bool SupportRefund => false;
/// <summary>
/// Gets a value indicating whether void is supported
/// </summary>
public bool SupportVoid => false;
/// <summary>
/// Gets a recurring payment type of payment method
/// </summary>
public RecurringPaymentType RecurringPaymentType => RecurringPaymentType.NotSupported;
/// <summary>
/// Gets a payment method type
/// </summary>
public PaymentMethodType PaymentMethodType => PaymentMethodType.Standard;
/// <summary>
/// Gets a value indicating whether we should display a payment information page for this plugin
/// </summary>
public bool SkipPaymentInfo => _cashOnDeliveryPaymentSettings.SkipPaymentInfo;
/// <summary>
/// Gets a payment method description that will be displayed on checkout pages in the public store
/// </summary>
public string PaymentMethodDescription
{
get
{
return _localizationService.GetResource("Plugins.Payment.CashOnDelivery.PaymentMethodDescription");
}
}
#endregion
}
}
The shipping method is saved as a GenericAttribute of the current customer. So, you can get via IGenericAttributeService (if you don't inject it in your PaymentProcessor class, you have to inject it). If we assume that the system name of your intended shipping method is "Nop.Shipping.PickupInStore", then we can hide the payment method like this:
public bool HidePaymentMethod(IList<ShoppingCartItem> cart)
{
var customer = cart.FirstOrDefault(item => item.Customer != null)?.Customer;
ShippingOption shippingOption = _genericAttributeService.GetAttribute<ShippingOption>(customer, NopCustomerDefaults.SelectedShippingOptionAttribute, _storeContext.CurrentStore.Id);
var shippingMethodSystemName = "Nop.Shipping.PickupInStore";
if (shippingOption!= null && shippingOption.ShippingRateComputationMethodSystemName.Equals(shippingMethodSystemName))
return true;
return false;
}

Generating a C# class from a JSON Schema using SwaggerHub and/or NSwagStudio

How do I use a Swagger API (JSON) to C# code generator like SwaggerHub or NSwagStudio to generate C# Client Code for a larger API such as Clio? (https://app.clio.com/api_v4.json).
These tools seem to work fine for smaller APIs, but when you put a large schema in they output code which does not compile and seems to have multiple issues.
/// <summary>Return the data for all triggers</summary>
/// <param name="x_API_VERSION">The [API minor version](#section/Minor-Versions). Default: latest version.</param>
/// <param name="x_BULK">An indicator if [bulk actions](#section/Bulk-Actions) should be performed.
/// When performing a bulk action, the id path parameter is not required.</param>
/// <param name="fields">The fields to be returned. See response samples for what fields are available. For more information see the [fields section](#section/Fields).</param>
/// <param name="is_requirements_required">Filter JurisdictionsToTrigger records to those which require addition requirements to be checked (usually specifying trigger time).</param>
/// <param name="is_served">Filter JurisdictionsToTrigger records to those which require a service type to be selected.</param>
/// <param name="jurisdiction_id">The unique identifier for the Jurisdiction.</param>
/// <param name="limit">A limit on the number of JurisdictionsToTrigger records to be returned. Limit can range between 1 and 200. Default: `200`.</param>
/// <param name="page_token">A token specifying which page to return.</param>
/// <param name="query">Wildcard search for `description` matching a given string.</param>
/// <returns>Ok</returns>
/// <exception cref="ClioAPIException">A server side error occurred.</exception>
public System.Threading.Tasks.Task<JurisdictionsToTriggerList> CourtRulesJurisdictionsId}Triggers.jsonAsync(string x_API_VERSION, bool? x_BULK, string fields, bool? is_requirements_required, bool? is_served, int jurisdiction_id, int? limit, string page_token, string query)
{
return CourtRulesJurisdictionsId}Triggers.jsonAsync(x_API_VERSION, x_BULK, fields, is_requirements_required, is_served, jurisdiction_id, limit, page_token, query, System.Threading.CancellationToken.None);
}
For instance, in the above routine, it adds a "}" to the name CourtRulesJurisdictions}Triggers
I have tried both SwaggerHub and NSwagStudio for this particular API and neither work. The NSwagStudio has the above issue and the SwaggerHub generates code which has this issue. At the end of a client API call to get data, this call to the JsonConvert.DeserializeObject fails. The data is in the Response. Content as I can see it in the debugger, and the type is set to the correct model, but no data is placed in the model.
try
{
return JsonConvert.DeserializeObject(response.Content, type, serializerSettings);
}
catch (Exception e)
{
throw new ApiException(500, e.Message);
}
I reduced the code to this, which doesn't even use anything but the generated model and it fails.
Dim x = "{""data"":{""name"":""Fred G. Jones"",""last_name"":""Jones"",""id"":345171548}}"
u = Newtonsoft.Json.JsonConvert.DeserializeObject(x, GetType(Clio_API.Model.UserShow))
This is the generated model UserShow
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.ComponentModel.DataAnnotations;
using SwaggerDateConverter = Clio_API.Client.SwaggerDateConverter;
namespace Clio_API.Model
{
/// <summary>
/// UserShow
/// </summary>
[DataContract]
public partial class UserShow : IEquatable<UserShow>, IValidatableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="UserShow" /> class.
/// </summary>
[JsonConstructorAttribute]
protected UserShow() { }
/// <summary>
/// Initializes a new instance of the <see cref="UserShow" /> class.
/// </summary>
/// <param name="Data">User Object Response (required).</param>
public UserShow(User Data = default(User))
{
// to ensure "Data" is required (not null)
if (Data == null)
{
throw new InvalidDataException("Data is a required property for UserShow and cannot be null");
}
else
{
this.Data = Data;
}
}
/// <summary>
/// User Object Response
/// </summary>
/// <value>User Object Response</value>
[DataMember(Name="data", EmitDefaultValue=false)]
public User Data { get; set; }
/// <summary>
/// Returns the string presentation of the object
/// </summary>
/// <returns>String presentation of the object</returns>
public override string ToString()
{
var sb = new StringBuilder();
sb.Append("class UserShow {\n");
sb.Append(" Data: ").Append(Data).Append("\n");
sb.Append("}\n");
return sb.ToString();
}
/// <summary>
/// Returns the JSON string presentation of the object
/// </summary>
/// <returns>JSON string presentation of the object</returns>
public string ToJson()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
/// <summary>
/// Returns true if objects are equal
/// </summary>
/// <param name="input">Object to be compared</param>
/// <returns>Boolean</returns>
public override bool Equals(object input)
{
return this.Equals(input as UserShow);
}
/// <summary>
/// Returns true if UserShow instances are equal
/// </summary>
/// <param name="input">Instance of UserShow to be compared</param>
/// <returns>Boolean</returns>
public bool Equals(UserShow input)
{
if (input == null)
return false;
return
(
this.Data == input.Data ||
(this.Data != null &&
this.Data.Equals(input.Data))
);
}
/// <summary>
/// Gets the hash code
/// </summary>
/// <returns>Hash code</returns>
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hashCode = 41;
if (this.Data != null)
hashCode = hashCode * 59 + this.Data.GetHashCode();
return hashCode;
}
}
/// <summary>
/// To validate all properties of the instance
/// </summary>
/// <param name="validationContext">Validation context</param>
/// <returns>Validation Result</returns>
IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> IValidatableObject.Validate(ValidationContext validationContext)
{
yield break;
}
}
}

How to automatically profile/time HttpWebRequests to a specific domain?

My C# WebAPI talks to a backend database (Couchbase) using HTTP requests. I have no control over the actual library that does the calls so I cannot simply time it from the code but I would like to save the timings of the calls to the database for SLA purposes.
Is there a way to intercept HTTP calls to a specific domain using Net.Tracing or something and save the timings of the calls? Something similar to what the Network tab of Chrome provides.
This is my crude solution to the problem. I am still looking for better solutions...
Enable System.Net logging in Web.config
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.Net" maxdatasize="1024">
<listeners>
<add name="NetTimingParserListener"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="NetTimingParserListener" type="..." />
</sharedListeners>
<switches>
<add name="System.Net" value="Verbose" />
</switches>
</system.diagnostics>
The above config will enable verbose logging which I will capture with a custom trace listener. This trace listener will parse the log files on the fly and attempt to correlate the network events & store the timings.
Next, I created an object to store the correlated events and calculate timing between them.
/// <summary>
/// Measure and store status and timings of a given Network request.
/// </summary>
public class RequestTrace
{
private Stopwatch _timer = new Stopwatch();
/// <summary>
/// Initializes a new instance of the <see cref="Object" /> class.
/// </summary>
public RequestTrace(string id, Uri url)
{
Id = new Stack<string>();
Id.Push(id);
Url = url;
IsFaulted = false;
}
/// <summary>
/// Any Id's that are associated with this request. Such as
/// HttpWebRequest, Connection, and associated Streams.
/// </summary>
public Stack<string> Id { get; set; }
/// <summary>
/// The Url of the request being made.
/// </summary>
public Uri Url { get; private set; }
/// <summary>
/// Time in ms for setting up the connection.
/// </summary>
public long ConnectionSetupTime { get; private set; }
/// <summary>
/// Time to first downloaded byte. Includes sending request headers,
/// body and server processing time.
/// </summary>
public long WaitingTime { get; private set; }
/// <summary>
/// Time in ms spent downloading the response.
/// </summary>
public long DownloadTime { get; private set; }
/// <summary>
/// True if the request encounters an error.
/// </summary>
public bool IsFaulted { get; private set; }
/// <summary>
/// Call this method when the request begins connecting to the server.
/// </summary>
public void StartConnection()
{
_timer.Start();
}
/// <summary>
/// Call this method when the requst successfuly connects to the server. Otherwise, fall <see cref="Faulted"/>.
/// </summary>
public void StopConnection()
{
_timer.Stop();
ConnectionSetupTime = _timer.ElapsedMilliseconds;
_timer.Reset();
}
/// <summary>
/// Call this method after connecting to the server.
/// </summary>
public void StartWaiting()
{
_timer.Start();
}
/// <summary>
/// Call this method after receiving the first byte of the HTTP server
/// response.
/// </summary>
public void StopWaiting()
{
_timer.Stop();
WaitingTime = _timer.ElapsedMilliseconds;
_timer.Reset();
}
/// <summary>
/// Call this method after receiving the first byte of the HTTP reponse.
/// </summary>
public void StartDownloadTime()
{
_timer.Start();
}
/// <summary>
/// Call this method after the response is completely received.
/// </summary>
public void StopDownloadTime()
{
_timer.Stop();
DownloadTime = _timer.ElapsedMilliseconds;
_timer = null;
}
/// <summary>
/// Call this method if an Exception occurs.
/// </summary>
public void Faulted()
{
DownloadTime = 0;
WaitingTime = 0;
ConnectionSetupTime = 0;
IsFaulted = true;
if (_timer.IsRunning)
{
_timer.Stop();
}
_timer = null;
}
/// <summary>
/// Returns a string that represents the current object.
/// </summary>
/// <returns>
/// A string that represents the current object.
/// </returns>
public override string ToString()
{
return IsFaulted
? String.Format("Request to node `{0}` - Exception", Url.DnsSafeHost)
: String.Format("Request to node `{0}` - Connect: {1}ms - Wait: {2}ms - Download: {3}ms", Url.DnsSafeHost,
ConnectionSetupTime, WaitingTime, DownloadTime);
}
}
System.Net does not really have a single ID that correlates to the same request. You could use the thread ID but that will break down quickly, so I needed to keep track of many different objects (HttpWebRequest, Connection, ConnectStream, etc.) and follow as they get associated with each other in the log. I do not know of any built-in .NET types that allow you to have multiple keys mapped to a single value, so I created this crude collection for my purposes.
/// <summary>
/// Specialized collection that associates multiple keys with a single item.
///
/// WARNING: Not production quality because it does not react well to dupliate or missing keys.
/// </summary>
public class RequestTraceCollection
{
/// <summary>
/// Internal dictionary for doing lookups.
/// </summary>
private readonly Dictionary<string, RequestTrace> _dictionary = new Dictionary<string, RequestTrace>();
/// <summary>
/// Retrieve an item by <paramref name="key"/>.
/// </summary>
/// <param name="key">Any of the keys associated with an item</param>
public RequestTrace this[string key]
{
get { return _dictionary[key]; }
}
/// <summary>
/// Add an <paramref name="item"/> to the collection. The item must
/// have at least one string in the Id array.
/// </summary>
/// <param name="item">A RequestTrace object.</param>
public void Add(RequestTrace item)
{
_dictionary.Add(item.Id.Peek(), item);
}
/// <summary>
/// Given an <paramref name="item"/> in the collection, add another key
/// that it can be looked up by.
/// </summary>
/// <param name="item">Item that exists in the collection</param>
/// <param name="key">New key alias</param>
public void AddAliasKey(RequestTrace item, string key)
{
item.Id.Push(key);
_dictionary.Add(key, item);
}
/// <summary>
/// Remove an <paramref name="item"/> from the collection along with any
/// of its key aliases.
/// </summary>
/// <param name="item">Item to be removed</param>
public void Remove(RequestTrace item)
{
while (item.Id.Count > 0)
{
var key = item.Id.Pop();
_dictionary.Remove(key);
}
}
}
And finally, it was a matter of creating the custom TraceListener and parsing the logged messages.
public class HttpWebRequestTraceListener : TraceListener
{
private readonly RequestTraceCollection _activeTraces = new RequestTraceCollection();
private readonly Regex _associatedConnection =
new Regex(#"^\[\d+\] Associating (Connection#\d+) with (HttpWebRequest#\d+)",
RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.Singleline);
private readonly Regex _connected = new Regex(#"^\[\d+\] (ConnectStream#\d+) - Sending headers",
RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.Singleline);
private readonly Regex _newRequest =
new Regex(#"^\[\d+\] (HttpWebRequest#\d+)::HttpWebRequest\(([http|https].+)\)",
RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.Singleline);
private readonly Regex _requestException = new Regex(#"^\[\d+\] Exception in (HttpWebRequestm#\d+)::",
RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.Singleline);
private readonly Regex _responseAssociated =
new Regex(#"^\[\d+\] Associating (HttpWebRequest#\d+) with (ConnectStream#\d+)",
RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.Singleline);
private readonly Regex _responseComplete = new Regex(#"^\[\d+\] Exiting (ConnectStream#\d+)::Close\(\)",
RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.Singleline);
private readonly Regex _responseStarted = new Regex(#"^\[\d+\] (Connection#\d+) - Received status line: (.*)",
RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.Singleline);
/// <summary>
/// When overridden in a derived class, writes the specified
/// <paramref name="message" /> to the listener you create in the derived
/// class.
/// </summary>
/// <param name="message">A message to write.</param>
public override void Write(string message)
{
// Do nothing here
}
/// <summary>
/// Parse the message being logged by System.Net and store relevant event information.
/// </summary>
/// <param name="message">A message to write.</param>
public override void WriteLine(string message)
{
var newRequestMatch = _newRequest.Match(message);
if (newRequestMatch.Success)
{
var requestTrace = new RequestTrace(newRequestMatch.Groups[1].Value,
new Uri(newRequestMatch.Groups[2].Value));
requestTrace.StartConnection();
_activeTraces.Add(requestTrace);
return;
}
var associatedConnectionMatch = _associatedConnection.Match(message);
if (associatedConnectionMatch.Success)
{
var requestTrace = _activeTraces[associatedConnectionMatch.Groups[2].Value];
_activeTraces.AddAliasKey(requestTrace, associatedConnectionMatch.Groups[1].Value);
return;
}
var connectedMatch = _connected.Match(message);
if (connectedMatch.Success)
{
var requestTrace = _activeTraces[connectedMatch.Groups[1].Value];
requestTrace.StopConnection();
requestTrace.StartWaiting();
return;
}
var responseStartedMatch = _responseStarted.Match(message);
if (responseStartedMatch.Success)
{
var requestTrace = _activeTraces[responseStartedMatch.Groups[1].Value];
requestTrace.StopWaiting();
requestTrace.StartDownloadTime();
return;
}
var responseAssociatedMatch = _responseAssociated.Match(message);
if (responseAssociatedMatch.Success)
{
var requestTrace = _activeTraces[responseAssociatedMatch.Groups[1].Value];
_activeTraces.AddAliasKey(requestTrace, responseAssociatedMatch.Groups[2].Value);
return;
}
var responseCompleteMatch = _responseComplete.Match(message);
if (responseCompleteMatch.Success)
{
var requestTrace = _activeTraces[responseCompleteMatch.Groups[1].Value];
requestTrace.StopDownloadTime();
_activeTraces.Remove(requestTrace);
// TODO: At this point the request is done, use this time to store & forward this log entry
Debug.WriteLine(requestTrace);
return;
}
var faultedMatch = _requestException.Match(message);
if (faultedMatch.Success)
{
var requestTrace = _activeTraces[responseCompleteMatch.Groups[1].Value];
requestTrace.Faulted();
_activeTraces.Remove(requestTrace);
// TODO: At this point the request is done, use this time to store & forward this log entry
Debug.WriteLine(requestTrace);
}
}
}
I believe what you are looking for is an action filter, you can see an example of it on the official asp.net site at:
http://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/understanding-action-filters-cs

Silverlight talking to a WCF using RIA Services Silverlight Client

My silverlight project has references to the RIA Services Silverlight Client and my .web application has access to RIAServices.Server.
I can't seem to find a good tutorial to learn how to connect these. Once I understand how to get the data from my NumberGenerator method. I can pick it up from there. I have three questions that I need some help with.
First, am I setting up this project correctly? I never done a project with RIA before.
Secondly what reference do I need to use ServiceContract(), FaultContract, and OperationContract? Most examples show that they are in the System.ServiceModel library. In this case with using the external library RIA Services Silverlight Client that is not the case. It throws a error saying I am missing a reference. What other libraries would have those three in it?
My last question is what URI do you use in the SystemDomainContext? Where I found the code at used this MyFirstRIAApplication-Web-EmployeeDomainService.svc but in my case I don't have anything that has a .svc extension. Would I use the .xap or .aspx?
Here is my Silverlight code
Here is my NumberGenerator Silverlight UserControl Page Code
public partial class NumberGenerator : UserControl
{
public NumberGenerator()
{
InitializeComponent();
GenerateNumber();
}
private void GenerateButton_Click(object sender, RoutedEventArgs e)
{
GenerateNumber();
}
private void GenerateNumber()
{
int result = 0
SystemClientServices systemclientservices = SystemClientServices.Instance;
result = systemclientservices.GenerateNumber();
NumberLabel.Content = result;
}
}
Here is my System Client Services class
private readonly static SystemClientServices _instance = new SystemClientServices();
private SystemDomainContext _domainContext = new SystemDomainContext();
private SystemClientServices() { }
public static SystemClientServices Instance
{
get
{
return _instance;
}
}
public int GenerateNumber()
{
//Code goes here to get the information from the Domainservices
LoadOperation load = this._domainContext.Load(this._domainContext.GetNumberGeneratorQuery(), LoadBehavior.KeepCurrent, false);
return Convert.ToInt32(load.Entities);
}
Here is my NumberGenerator class on the silverlight local project
public sealed partial class NumberGenerator : Entity
{
private static readonly NumberGenerator _instance = new NumberGenerator();
public int NumberGenerated { get; set; }
public NumberGenerator()
{
NumberGenerated = 0;
}
public static NumberGenerator Instance
{
get
{
return _instance;
}
}
}
Here is System Domain Conext class on the silverlight local project
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel.DomainServices;
using System.ServiceModel.DomainServices.Client;
using System.ServiceModel.DomainServices.Client.ApplicationServices;
using System.ServiceModel.Web;
using System.ServiceModel;
public sealed partial class SystemDomainConext : DomainContext
{
#region Extensibility Method Definitions
/// <summary>
/// This method is invoked from the constructor once initialization is complete and
/// can be used for further object setup.
/// </summary>
partial void OnCreated();
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="EmployeeDomainContext"/> class.
/// </summary>
public SystemDomainConext() : this(new WebDomainClient<ISystemDomainServiceContract>(new Uri("MyFirstRIAApplication-Web-EmployeeDomainService.svc", UriKind.Relative)))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EmployeeDomainContext"/> class with the specified service URI.
/// </summary>
/// <param name="serviceUri">The EmployeeDomainService service URI.</param>
public SystemDomainConext(Uri serviceUri) : this(new WebDomainClient<ISystemDomainServiceContract>(serviceUri))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EmployeeDomainContext"/> class with the specified <paramref name="domainClient"/>.
/// </summary>
/// <param name="domainClient">The DomainClient instance to use for this DomainContext.</param>
public SystemDomainConext(DomainClient domainClient) : base(domainClient)
{
this.OnCreated();
}
/// <summary>
/// Gets the set of <see cref="Employee"/> entity instances that have been loaded into this <see cref="EmployeeDomainContext"/> instance.
/// </summary>
public EntitySet<NumberGenerator> GeneratedNumber
{
get
{
return base.EntityContainer.GetEntitySet<NumberGenerator>();
}
}
/// <summary>
/// Gets an EntityQuery instance that can be used to load <see cref="Employee"/> entity instances using the 'GetEmployee' query.
/// </summary>
/// <returns>An EntityQuery that can be loaded to retrieve <see cref="Employee"/> entity instances.</returns>
public EntityQuery<NumberGenerator> GetNumberGeneratorQuery()
{
this.ValidateMethod("GetGeneratedNumber", null);
return base.CreateQuery<NumberGenerator>("GetNumberGenerator", null, false, true);
}
/// <summary>
/// Creates a new EntityContainer for this DomainContext's EntitySets.
/// </summary>
/// <returns>A new container instance.</returns>
protected override EntityContainer CreateEntityContainer()
{
return new NumberGeneratorDomainContextEntityContainer();
}
/// <summary>
/// Service contract for the 'EmployeeDomainService' DomainService.
/// </summary>
[ServiceContract()]
public interface ISystemDomainServiceContract
{
/// <summary>
/// Asynchronously invokes the 'GetEmployee' operation.
/// </summary>
/// <param name="callback">Callback to invoke on completion.</param>
/// <param name="asyncState">Optional state object.</param>
/// <returns>An IAsyncResult that can be used to monitor the request.</returns>
[FaultContract(typeof(DomainServiceFault), Action="http://tempuri.org/EmployeeDomainService/GetEmployeeDomainServiceFault", Name="DomainServiceFault", Namespace="DomainServices")]
[OperationContract(AsyncPattern=true, Action="http://tempuri.org/EmployeeDomainService/GetEmployee", ReplyAction="http://tempuri.org/EmployeeDomainService/GetEmployeeResponse")]
[WebGet()]
IAsyncResult GetGeneratedNumber(AsyncCallback callback, object asyncState);
/// <summary>
/// Completes the asynchronous operation begun by 'BeginGetEmployee'.
/// </summary>
/// <param name="result">The IAsyncResult returned from 'BeginGetEmployee'.</param>
/// <returns>The 'QueryResult' returned from the 'GetEmployee' operation.</returns>
QueryResult<NumberGenerator> EndGetGeneratedNumber(IAsyncResult result);
/// <summary>
/// Asynchronously invokes the 'SubmitChanges' operation.
/// </summary>
/// <param name="changeSet">The change-set to submit.</param>
/// <param name="callback">Callback to invoke on completion.</param>
/// <param name="asyncState">Optional state object.</param>
/// <returns>An IAsyncResult that can be used to monitor the request.</returns>
[FaultContract(typeof(DomainServiceFault), Action="http://tempuri.org/EmployeeDomainService/SubmitChangesDomainServiceFault", Name="DomainServiceFault", Namespace="DomainServices")]
[OperationContract(AsyncPattern=true, Action="http://tempuri.org/EmployeeDomainService/SubmitChanges", ReplyAction="http://tempuri.org/EmployeeDomainService/SubmitChangesResponse")]
IAsyncResult BeginSubmitChanges(IEnumerable<ChangeSetEntry> changeSet, AsyncCallback callback, object asyncState);
/// <summary>
/// Completes the asynchronous operation begun by 'BeginSubmitChanges'.
/// </summary>
/// <param name="result">The IAsyncResult returned from 'BeginSubmitChanges'.</param>
/// <returns>The collection of change-set entry elements returned from 'SubmitChanges'.</returns>
IEnumerable<ChangeSetEntry> EndSubmitChanges(IAsyncResult result);
}
internal sealed class NumberGeneratorDomainContextEntityContainer : EntityContainer
{
public NumberGeneratorDomainContextEntityContainer()
{
this.CreateEntitySet<NumberGenerator>(EntitySetOperations.Edit);
}
}
}
Here is my System Domain Services class that is on the Silverlight.web
[EnableClientAccess()]
public class SystemDomainServices : DomainService
{
private NumberGenerator numberGenerator = NumberGenerator.Instance;
public int NumberGenerate()
{
return numberGenerator.NumberGenerated;
}
}
Here is the NumberGenerator class on the silverlight.web
private static readonly NumberGenerator _instance = new NumberGenerator();
[Key]
public int NumberGenerated { get; set; }
public NumberGenerator()
{
NumberGenerated = GenerateNumber();
}
public static NumberGenerator Instance
{
get
{
return _instance;
}
}
public int GenerateNumber()
{
string db_date = "";
int db_num = 0;
string todaysdate = "";
int temp_num = db_num;
int result = 0;
using (SqlConnection connection = new SqlConnection(DBConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand("SELECT * FROM table", connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
db_date = reader.GetString(0);
db_num = (int)(reader.GetSqlInt32(1));
todaysdate = DateTime.Now.ToString("yMMdd");
temp_num = db_num;
}
reader.Close();
}
if (todaysdate != db_date)
{
using (SqlCommand dateUpate = new SqlCommand("UPDATE table SET tsDate='" + todaysdate + "' WHERE tsDate='" + db_date + "'", connection))
{
dateUpate.ExecuteNonQuery();
}
db_num = 0;
db_date = todaysdate;
}
db_num++;
using (SqlCommand numUpate = new SqlCommand("UPDATE table SET tsNum='" + db_num + "' WHERE tsNum='" + temp_num + "'", connection))
{
numUpate.ExecuteNonQuery();
}
result = Convert.ToInt32(db_date + db_num.ToString().PadLeft(3, '0'));
connection.Close();
connection.Dispose();
}
return result;
}
}
The answer to question two you might be have to go to Tools at the top, NuGet Package Manager, Package Management Console, and then type the following command to install the package for those three functions.
PM> Install-Package RIAServices.Silverlight.DomainDataSource

Categories