How can I implement Bulk insert in ASP.NET Core 1.0? - asp.net-core

I want to import the data from database in .csv format and want to export .csv into my SQL server/Oracle database. I am using ASP.NET Core RC 1 at this moment. I looked into SQLBulkCopy class but the issue is that it is not ported to ASP.NET Core.
Can someone tell me how can I do it or is there any other compatible nuget package available (with ASP.NET Core)?

Microsoft has added SqlBulkCopy to .NET Core, so you can bring it in as part of the System.Data.SqlClient NuGet package. I opted to use FastMember by #MarcGravell to handle the work of mapping my data, but you don't have to.
FastMember will take a collection of parameters, and a collection of objects, and pull the values off your objects that map to your collection of parameters. Really simplifies the code.
private async Task OutputPerformanceDataToStorage(List<PerformanceData> dataToSave)
{
var storageParameters = new[]
{
nameof(PerformanceData.PerformanceId),
nameof(PerformanceData.IPAddress),
nameof(PerformanceData.ControllerName),
nameof(PerformanceData.ActionName),
nameof(PerformanceData.ActionParameters),
nameof(PerformanceData.ViewPath),
nameof(PerformanceData.TotalRequestTimeInMilliseconds),
nameof(PerformanceData.RequestStartedTimestamp),
nameof(PerformanceData.RequestEndedTimestamp),
nameof(PerformanceData.CreatedDateTime),
};
var sqlCopy = new SqlBulkCopy(this.connectionString, SqlBulkCopyOptions.Default);
sqlCopy.DestinationTableName = "[Performance]";
using (var reader = ObjectReader.Create(dataToSave, storageParameters))
{
await sqlCopy.WriteToServerAsync(reader);
}
}
internal class PerformanceData
{
public Guid PerformanceId;
public double TotalRequestTimeInMilliseconds;
public long RequestStartedTimestamp;
public long RequestEndedTimestamp;
public string IPAddress;
public string ControllerName;
public string ActionName;
public string ViewPath;
public string ActionParameters;
public List<string> ActionParametersList;
public DateTime CreatedDateTime;
}

.NET Standard 2.0 now supports many of the .NET framework libraries which means that SqlBulkCopy class can be used with ASP.NET Core. Dataset, Datatables and SQLBulkCopy will do the job for bulk insertion. Find more details about .NETStandard 2.0 here.

Related

Adding DbContext for list of context types at runtime

To implement a plug-in system in a AspNet Core Mvc app, I would like a non-generic method to add a data context from a list of assemblies loaded dynamically at runtime, taking a Type parameter like this:
foreach(Type tp in pluginContexts)
{
services.AddDbContext(tp, options => ...);
}
instead of the usual
services.AddDbContext<PluginDataContext>(options => ...);
That's because for dynamically loaded assemblies, I can not provide the TContext type parameter to the AddDbContextPool method, since that's statically compiled and not available at compile time.
Background
This is for a larger Asp.Net Core MVC app. The plugins must be able to both access the main database of the overall app and a separate database of their own.
Plugin assemblies, containing domain code and their private database context are to be dropped in a specified directory.
The main app loads the plugin assembly dynamically upon startup.
The way I am solving this now is to have each controller get the IConfiguration instance injected, obtain the appropriate connection string from the config, and the database context is instantiated in the controller. Not so nice but does work.
One can easily inject a general class into the Services collection with AddScoped<>, and then use it as a sort of ServiceLocator - however, that is considered an antipattern.
I looked into the source code for AddDbContext but honestly I am lost.
Is there any simple way to achieve this?
Solved it by creating an extensibility point in the plugin assembly.
Define an interface in the main app, which all plugins must implement.
public interface IPluginContextRegistration
{
void RegisterContext(ref IServiceCollection services, Action<DbContextOptionsBuilder> optionsAction);
String GetDatabaseName();
}
Create a class implementing this interface (in the plugin). It has access to the type of its private database context, thus can use the generic AddDbContext method:
public class DatabaseRegistration : IPluginContextRegistration
{
public void RegisterContext(ref IServiceCollection services, Action<DbContextOptionsBuilder> optionsAction)
{
services.AddDbContext<Test1DbContext>(optionsAction);
}
public String GetDatabaseName()
{
return "test-plugin-db";
}
}
Then in the main app ASP.Net Startup.cs file, add following code, which calls the RegisterContext() method for each plugin. For example, if you want to use Sql Server:
void RegisterPluginDbContexts(ref IServiceCollection services, List<Assembly> assemblyList)
{
IEnumerable<IPluginContextRegistration> registrars = new List<IPluginContextRegistration>();
foreach (Assembly assembly in assemblyList)
{
registrars = registrars.Concat(GetClassInstances<IPluginContextRegistration>(assembly));
}
foreach (var reg in registrars)
{
String name = reg.GetDatabaseName();
String connStr = Configuration.GetConnectionString(name);
reg.RegisterContext(ref services, options => options.UseSqlServer(connStr));
}
}
For completeness - the method "GetClassInstances" is just a helper method using Reflection to obtain an instance of classes implementing the specified interface.
So it's simple after all - no need for re-writing framework code .

Properties of user-defined struct not deserialized in .NET Core 3.0 web API (works in .NET Core 2.2)

I have an ASP.NET Core web API project targeting .NET Core 3.0 with the following controller:
public class FooController : ControllerBase
{
[HttpPost]
public ActionResult Post(Foo foo) => Ok()
}
Foo is defined in a separate library as:
public struct Foo
{
public int Bar { get; }
public Foo(int bar) => Bar = bar;
}
I call the API from a console app with:
new HttpClient().PostAsJsonAsync("http://localhost:55555/api/foo", new Foo(1)).Wait();
When the controller method is entered, foo.Bar has the default value of 0. I expect it to be 1.
This used to work as expected in .NET Core 2.2. The JSON deserializer handles properties with private setters on structs via an overloaded constructor with parameter names matching the property names (case-insensitive).
This no longer work in .NET Core 3.0 with basic structs (EDIT: due to this as pointed out by Martin Ullrich). However, if I use a standard struct type such as DateTime, it works fine. Is there something additional I must now do to my struct that DateTime for instance already supports? I've already tried implementing ISerializable on Foo with the code below, but that didn't work.
public Foo(SerializationInfo info, StreamingContext context)
{
Bar = (int)info.GetValue("bar", typeof(int));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("bar", Bar, typeof(int));
}
Any help would be greatly appreciated.
The new System.Text.Json APIs do not support all the features that Newtonsoft.Json ("Json.NET") does, including deserialisation of read-only properties.
If you need this feature, switch to using Newtonsoft.Json as described in the Migrate from ASP.NET Core 2.2 to 3.0 Guide:
services.AddMvc()
.AddNewtonsoftJson();
or
services.AddControllers()
.AddNewtonsoftJson();
DateTime is already known by the System.Text.Json stack in 3.0 and there also is a JsonConverter<T> implementation for it: JsonConverterDateTime.
For creating custom converters and registering them for ASP.NET Core, see https://stackoverflow.com/a/57334833/784387

Create Custom HTML Helper in ASP.Net Core

I want to create my own custom HTML Helper like the ones used in ASP.NET MVC, but I haven't been able to find how to implement them in the correct way.
I have found how to create custom Tag Helpers but not HTML Helpers. How do I create my own custom HTML Helpers?
For me I thought my HTML helpers weren't working until I spotted that the extension method is now on IHtmlHelper not HtmlHelper.
So for .net core:
public static IHtmlContent CheckboxListFor<TModel>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, List<CheckboxListItem>>> expression) ...
Instead of for .net:
public static HtmlString CheckboxListFor<TModel>(this HtmlHelper<TModel> html,
Expression<Func<TModel, List<CheckboxListItem>>> expression) ...
EDIT: I've also updated the return type for .net core to be IHtmlContent as using something like HtmlContentBuilder is a nicer way to compose HTML content and returning that returns IHtmlContent
HTML Helpers look to be supported in ASP.NET Core and are awaiting documentation:
https://learn.microsoft.com/en-au/aspnet/core/mvc/views/html-helpers
[Edit:] Since answering, the above page no longer exists. I'd say HTML Helpers, while they work, are no longer "supported" in ASP.NET Core.
Looking at the ASP.NET Core source they work fairly similarly to older versions of ASP.NET MVC:
https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.ViewFeatures/src/Rendering/HtmlHelperDisplayExtensions.cs
Example
MyHTMLHelpers.cs:
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
namespace MyApp.Helpers
{
public static class MyHTMLHelpers
{
public static IHtmlContent HelloWorldHTMLString(this IHtmlHelper htmlHelper)
=> new HtmlString("<strong>Hello World</strong>");
public static String HelloWorldString(this IHtmlHelper htmlHelper)
=> "<strong>Hello World</strong>";
}
}
_ViewImports.cshtml (second line is the important change):
#using MyApp
#using MyApp.Helpers
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
MyView.cshtml:
<div>#Html.HelloWorldHTMLString()</div>
<div>#Html.HelloWorldString()</div>
Outputs:
Hello World
<strong>Hello World</strong>
Here is an example for .Net Core 2 using TagBuilders
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.IO;
public static IHtmlContent HelloWorld(this IHtmlHelper html, string name)
{
var span = new TagBuilder("span");
span.InnerHtml.Append("Hello, " + name + "!");
var br = new TagBuilder("br") {TagRenderMode = TagRenderMode.SelfClosing};
string result;
using (var writer = new StringWriter())
{
span.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
br.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
result = writer.ToString();
}
return new HtmlString(result);
}
I was never able to get HtmlHelper extension methods to work, I always recieved:
'IHtmlHelper' does not contain a definition for 'MethodName' and no extension method 'MethodName' accepting a first argument of type 'IHtmlHelper' could be found (are you missing a using directive or an assembly reference?)
Even though I had the proper namespace in my _ViewImports.cshtml file. So I decided to use the ability of Razor pages to now support injecting services that have been registered for dependency injection. As an example I have the need to inject some values from my configuration file into my _Layout.cshtml file. So I did the following:
1) Defined a IConfigurationHelperService interface:
public interface IConfigurationHelperService
{
string GetApiUrl();
}
2) Defined an implementation of that interface in a ConfigurationHelperSerivce class (which itself is using dependency injection to get the regular configuration class):
public class ConfigurationHelperService : IConfigurationHelperService
{
public ConfigurationHelperService(IConfiguration configuration)
{
Configuration = configuration;
}
private IConfiguration Configuration { get; }
public string GetApiUrl()
{
return GetConfigurationValue(ApiUrl);
}
private string GetConfigurationValue(string key)
{
var value = Configuration[key];
if (value.IsNullOrEmpty()) throw new KeyNotFoundException($"Configruation does not contain an instance of {key}");
return value;
}
}
3) Registered the service for injection via ConfigureServices in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfigurationHelperService, ConfigurationHelperService>();
services.AddMvc();
}
4) Added the proper namespace as a using statement into my _ViewImports.cshtml file.
5) Used the #inject keyword to define it for use in the _Layout.cshtml file.
#inject IConfigurationHelperService ConfigHelper
<!DOCTYPE html>
<html>
...
#ConfigHelper.GetApiUrl()
...
</html>
It worked great for me, and I can see a lot more uses for this on simpler pages where defining models would be too much work.
Well i guess this answer won't be noticed but here's what i came up with using service registrations:
I hope it helps someone.
Register the service:
services.AddTransient<IHtmlHelperFactory, HtmlHelperFactory>();
Use the service:
var helper = HttpContext.RequestServices.GetRequiredService<IHtmlHelperFactory>().Create();
Interface:
public interface IHtmlHelperFactory
{
IHtmlHelper Create();
}
Implementation:
public class HtmlHelperFactory : IHtmlHelperFactory
{
private readonly IHttpContextAccessor _contextAccessor;
public class FakeView : IView
{
/// <inheritdoc />
public Task RenderAsync(ViewContext context)
{
return Task.CompletedTask;
}
/// <inheritdoc />
public string Path { get; } = "View";
}
public HtmlHelperFactory(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
/// <inheritdoc />
public IHtmlHelper Create()
{
var modelMetadataProvider = _contextAccessor.HttpContext.RequestServices.GetRequiredService<IModelMetadataProvider>();
var tempDataProvider = _contextAccessor.HttpContext.RequestServices.GetRequiredService<ITempDataProvider>();
var htmlHelper = _contextAccessor.HttpContext.RequestServices.GetRequiredService<IHtmlHelper>();
var viewContext = new ViewContext(
new ActionContext(_contextAccessor.HttpContext, _contextAccessor.HttpContext.GetRouteData(), new ControllerActionDescriptor()),
new FakeView(),
new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary()),
new TempDataDictionary(_contextAccessor.HttpContext, tempDataProvider),
TextWriter.Null,
new HtmlHelperOptions()
);
((IViewContextAware)htmlHelper).Contextualize(viewContext);
return htmlHelper;
}
}
This has been well explained by Danny van der Kraan in his blog post here. The answer below is an extract from this post:
ASP.NET Core 1.0 [MVC 6] comes with a new exciting feature called TagHelpers. In ASP.Net Core 1.0 there is no concept of HTML Helper like in MVC.
What are TagHelpers?
TagHelpers can be seen as the evolution of HTML helpers which were introduced with the launch of the first MVC framework. To provide context you have to imagine that with classic ASP the only way you could automate the generation of HTML is via custom subroutines. After that ASP.NET came with server controls, with view states as biggest plus, to simulate the look and feel of desktop applications and help with the transition for desktop developers. But we all know what happens when we try to jam squares in to round holes. We had to face the fact that web development is nothing like desktop development. To get in line with proper web development the ASP.NET MVC framework was launched with HTML helpers to automate the HTML output. But HTML helpers never really gelled, especially not with front end developers and designers. One of the main pet peeves was that it made you switch a lot from angle brackets (HTML, CSS) to C# (Razor syntax) during work on views, which made the experience unnecessarily uncomfortable. [MVC 6] wants to address this and some smaller issues by introducing TagHelpers. Example
HTML helper:
#Html.ActionLink(”Home”, ”Index”, ”Home”)
With the anchor TagHelper this would look like:
<a asp-action="Index" asp-controller="Home">Home</a>
PS: Please note that asp- is just a convention, but more on that later.
The output rendered in the browser is the same for both:
Home
PS: Provided the default route has not been altered.
For more information about TagHelpers click here
To create a custom HTML helper you have create a static class and static method.
below example is for a custom HTML helper for submit button.
namespace TagHelpers.Helpers
{
public static class CustomHtmlHelpers
{
public static IHtmlContent SubmitButton(this IHtmlHelper htmlHelper, string value, string name )
{
string str = "<input type='submit' value ='"+ value +"'name='"+ name +"' />";
return new HtmlString(str);
}
}
}
Make sure you add below using statements.
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
To access the helper everywhere on the page you need to add the namespace in to the viewimports.cshtml file
#using TagHelpers.Helpers
Now, You can now use it on the page where you want to define a button.
<div>
#Html.SubmitButton("Login", "Command")
#Html.SubmitButton("Cancel", "Command")
</div>
Here is an example to get Enum name based on the Enum value in view. Custom HTML Helper for Enum Type
public static IHtmlContent DisplayEnumFor(this IHtmlHelper htmlHelper, string value, Type enumType)
{
if (htmlHelper == null)
throw new ArgumentNullException(nameof(htmlHelper));
if (value == null)
throw new ArgumentNullException(nameof(value));
if (!enumType.IsEnum)
throw new ArgumentException("Type must be an enumerated type");
foreach (var item in Enum.GetValues(enumType))
if (((int)item).ToString().Equals(value.Trim()))
return new HtmlString(item.ToString());
return new HtmlString(value);
}
Kept it simple but renders as expected. Make sure you have the right attributes set for the right elements. Please add suggestions if needs improvement or give your votes if it looks good.
public static class IconExtensions
{
public static IHtmlContent CCIcon(string iconName, string? toolTip = null)
{
return new HtmlString($"<img src=\"/img/{iconName}.png\" alt=\"{iconName}\" class=\"img-ca-annexicons\" title=\"{toolTip??iconName}\" />");
}
}

How to keep separate membership filter annotation in MVC 4 project

My solution architecture is as follow:
MVC 4 - presentation layer
Manager class library
DAL library
common DTO project library.
Now, I have added simple membership related classes and implemented.
Here, Problem is - InitializeSimpleMembership filter is existed into MVC 4 project and it contains - DBCONTEXT object... which is wrong as DBCONTEXT object or any DAL reference should not be exist into MVC 4 and I want to keep these separate into DAL project only.
Below is the filter code:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Ensure ASP.NET Simple Membership is initialized only once per app start
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<FinalEFFirstContext>(null);
try
{
using (var context = new FinalEFFirstContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
if (!WebSecurity.Initialized)
{
WebSecurity.InitializeDatabaseConnection("FinalEFFirstContext", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
if (!WebSecurity.ConfirmAccount("admin#mydom.com") && !WebSecurity.UserExists("admin#mydom.com"))
{
WebSecurity.CreateUserAndAccount("admin#mydom.com", "password");
}
if (!Roles.RoleExists("Administrator"))
{
Roles.CreateRole("Administrator");
Roles.AddUserToRole("admin#mydom.com", "Administrator");
}
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
Please guide me how I could separate this filter ?
Do I have to move this class into Manager class library and add these all MVC reference there ?
Thank You
Yes, you can consider moving the InitializeSimpleMembershipAttribute into your DAL layer (where you context class reside).
IMO it is fine to have a reference to DAL into your web project as long as you are depending on abstraction to access persistent store. For example, I derive my data context from IDataContext. The current datacontext which implement IDataContext interface uses EF as ORM. But tomorrow if we choose to switch to another ORM say NHibernate, all we need to do is implement IDataContext and change the dependency to resolve to new DataContext.
So you are right web project should not know how and from where we are accessing the data. That can be achieved by not giving a reference to EntityFramwork in web project. DAL reference is fine as long as web project does not get affected if you choose to change your ORM or data access technologies.
I can show you my solution structure which shows not reference to EF and filter in DAL, if it helps you:

.NET 4.5.1 WCF Serialization exception

Our LOB application is a client server application which uses CSLA business objects, those business objects are being serialized using the NetDataContractSerializer. The server side is running on WCF and the client has endpoints.
This all works when the client software is running from Windows 7 or Windows 8 having .NET 4.5 installed.
When running the client software on Windows 8 or Windows 8.1 with the latest .NET 4.5.1 Framework the following exception occurs.
The formatter threw an exception while trying to deserialize the
message: There was an error while trying to deserialize parameter
http://ws.lhotka.net/WcfDataPortal:FetchResult. The InnerException
message was 'Error in line 1 position 11619. 'Element'
'm_serializationArray' from namespace
'http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not
expected. Expecting element 'm_keyRehashCount'.'. Please see
InnerException for more details.
The most inner exception is
Error in line 1 position 11619. 'Element' 'm_serializationArray' from
namespace 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
is not expected. Expecting element 'm_keyRehashCount'.
I cannot find anything about this on stackoverflow or on google, i have posted this same question on the CSLA forums and perhaps i should also post it on Connect. But maybe i'm lucky here?
I need some time to backup my development environment before i update the .NET Framework to 4.5.1
I can think of two possible solutions:
upgrade the 2008 server to .NET 4.5.1.
force the client software to use .NET 4.5
Is it possible to force the client software to use .NET 4.5 only?
Any other idea's?
I can reproduce this issue from my end. I would like to give a few facts to see if this would help you in the meantime.
NetDataContractSerializer is more restrictive than a DataContractSerializer as per the documentation.
The NetDataContractSerializer differs from the DataContractSerializer in one important way: the NetDataContractSerializer includes CLR type information in the serialized XML, whereas the DataContractSerializer does not. Therefore, the NetDataContractSerializer can be used only if both the serializing and deserializing ends share the same CLR types.
I believe the type ConcurrentDictionary in 4.5.1 has added a property or member variable named m_keyRehashCount which is not found in the 4.5 version of the ConcurrentDictionary. While trying to de-serialize this object on a 4.5.1 machine – the serializer expects this missing property resulting in this exception.
<m_keyRehashCount>0</m_keyRehashCount>
Here are a few ways to solve this problem:
Upgrade your server machine as well to 4.5.1. .net 4.5.1 is a free upgrade to .net 4.5 which also has fixes for some compat issues found in .net 4.5.
Use DataContractSerializer instead of NetDataContractSerializer as this
does not expect the exact same CLR types at both serializing and
deserializing ends.
Change to use Dictionary instead
of a ConcurrentDictionary as I see this type works
fine.
If you have previously serialized objects (serialized with pre 4.5.1) which contain ConcurrentDictionary you can deserialize it in 4.5.1 using the following example.
This example only help deserializing already serialized ConcurrentDictionary objects by creating new class which can deserialize using the ConcurrentDictionary serialization XML, see also other answers.
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using ClassLibrary1.Model;
namespace SerializaerDesrializer
{
[DataContract]
public class CompositeDictionaryHolder
{
// Old serialized data member:
//[DataMember]
//private MyConcurrentDictionary<int, string> _concuurentDictionary = new MyConcurrentDictionary<int, string>();
private ConcurrentDictionary<int, string> _concuurentDictionaryInternal = new ConcurrentDictionary<int, string>();
[DataMember]
private InternalArray _concuurentDictionary;
public CompositeDictionaryHolder()
{
// Just an example:
_concuurentDictionaryInternal.TryAdd(1, "1");
_concuurentDictionaryInternal.TryAdd(2, "2");
_concuurentDictionaryInternal.TryAdd(3, "3");
}
/// <summary>
/// Get the data array to be serialized
/// </summary>
[OnSerializing]
private void OnSerializing(StreamingContext context)
{
// save the data into the serialization array to be saved
_concuurentDictionary = new InternalArray(_concuurentDictionaryInternal.ToArray());
}
/// <summary>
/// Construct the dictionary from a previously seiralized one
/// </summary>
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
_concuurentDictionaryInternal = new ConcurrentDictionary<int, string>(_concuurentDictionary.m_serializationArray);
}
}
[DataContract(
Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public class InternalArray
{
public InternalArray()
{
}
public InternalArray(KeyValuePair<int, string>[] serializationArray)
{
m_serializationArrayInternal = serializationArray;
}
[DataMember]
public KeyValuePair<int, string>[] m_serializationArray
{
get { return m_serializationArrayInternal; }
set { m_serializationArrayInternal = value; }
}
private KeyValuePair<int, string>[] m_serializationArrayInternal;
}
}