Xamarin.Forms custom entry renderer set entry scrollable on Android - xamarin.forms

I have a custom renderer for a Xamarin entry and I have added this.Control.VerticalScrollBarEnabled = true; inside of the OnElementChanged inside of the android renderer but I can not see a scroll bar.
I have done similar on the iOS side this.Control.ScrollEnabled = true; and it works.
Am I missing something? thank you
Android Custom renderer code
using Android.Content;
using Android.Graphics.Drawables;
using NGT.Views.ReusableViews;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(BorderedEditor), typeof(NGT.Droid.BorderedEditorRenderer))]
namespace NGT.Droid
{
/// <summary>
/// Boardered editor renderer.
/// </summary>
public class BorderedEditorRenderer : EditorRenderer
{
/// <summary>
/// Initializes a new instance of the <see cref="BorderedEditorRenderer"/> class.
/// </summary>
/// <param name="context">Context.</param>
public BorderedEditorRenderer(Context context)
: base(context)
{
}
/// <summary>
/// Ons the element changed.
/// </summary>
/// <param name="e">E.</param>
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
this.Control.VerticalScrollBarEnabled = true;
}
if (e.OldElement == null)
{
GradientDrawable gd = new GradientDrawable();
gd.SetCornerRadius(5);
gd.SetStroke(2, Constants.AppBlue.ToAndroid());
this.Control.Background = gd;
this.Control.ImeOptions = Android.Views.InputMethods.ImeAction.Done;
}
}
}
} ```

Related

I have a very strange question with xamarin.form and libvlcsharp

When I create LibVLC and MediaPlayer objects in the constructor and play the video, there is only sound but no image. When I create LibVLC and MediaPlayer objects in the'Play' function, there are sounds and images. I don't want to create a MediaPlayer object every time the play function is called. what should I do?
using System;
using System.ComponentModel;
using System.Windows.Input;
using LibVLCSharp.Shared;
using static Xamarin.Essentials.Permissions;
namespace MediaElement
{
/// <summary>
/// Represents the main viewmodel.
/// </summary>
public class MainViewModel : INotifyPropertyChanged
{
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Initializes a new instance of <see cref="MainViewModel"/> class.
/// </summary>
public MainViewModel()
{
Core.Initialize();
LibVLC = new LibVLC();
MediaPlayer = new MediaPlayer(LibVLC) { EnableHardwareDecoding = true };
}
private LibVLC _libVLC;
/// <summary>
/// Gets the <see cref="LibVLCSharp.Shared.LibVLC"/> instance.
/// </summary>
public LibVLC LibVLC
{
get => _libVLC;
private set => Set(nameof(LibVLC), ref _libVLC, value);
}
private MediaPlayer _mediaPlayer;
/// <summary>
/// Gets the <see cref="LibVLCSharp.Shared.MediaPlayer"/> instance.
/// </summary>
public MediaPlayer MediaPlayer
{
get => _mediaPlayer;
private set => Set(nameof(MediaPlayer), ref _mediaPlayer, value);
}
/// <summary>
/// Initialize LibVLC and playback when page appears
/// </summary>
public void Play(String path)
{
MediaPlayer.Play(new LibVLCSharp.Shared.Media(LibVLC, new Uri(path)));
}
private void Set<T>(string propertyName, ref T field, T value)
{
if (field == null && value != null || field != null && !field.Equals(value))
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
You only sent half of your code, we don't know how you are using your VideoView control.
As a general rule of thumb:
How do you attach the MediaPlayer to your view?
Do you properly wait for the view to be visible before calling Play?
Have a look at the samples here and compare to see what you did wrong.

Xamarin.forms Material entry placeholder size

In my xamarin.forms App I am using material entry provided by xamarin.The control works fine. But how can I change the fontsize of placeholder?In ios the font size of placeholder is perfect, but in android it is much larger. And also the underline of the entry is little more in the left side.How to reduce the gap and align placeholder and underline equally(Refer Image)
What I Have done
What I am trying to achieve
My entry
<Entry x:Name="CustomerEntry" Visual="Material" FontSize="Small" Placeholder="Customer Name" HorizontalOptions="FillAndExpand" BackgroundColor="Transparent" TextColor="White" PlaceholderColor="White" Margin="0,0,0,0" ></Entry>
Any help is appreciated
For the font size, I believe that you'll need to custom render. See this answer for details on how to do that. Make sure to inherit from the Material Render.
To solve the left alignment issue, I couldn't find a good solution that worked for both Android and iOS, so what I did was to suck the left margin of the entry over and then use a box view to cover the underline so everything looks left aligned. I had do this in multiple places, so I created a custom control. The downside to this was passing all the bindings through.
My custom control Xaml:
<?xml version="1.0" encoding="UTF-8" ?>
<Grid x:Class="x.x.x.Controls.MaterialControls.MaterialEntry"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Name="MaterialEntryComponent"
Margin="-16,0,0,0"
Focused="OnComponentFocused">
<Entry x:Name="MaterialEntryEntry"
Grid.Row="0"
BackgroundColor="{Binding EntryBackgroundColor}"
BindingContext="{x:Reference MaterialEntryComponent}"
Completed="OnEntryCompleted"
FontFamily="{Binding FontFamily}"
FontSize="{Binding FontSize}"
IsPassword="{Binding IsPassword}"
IsSpellCheckEnabled="{Binding IsSpellCheckEnabled}"
IsTextPredictionEnabled="{Binding IsTextPredictionEnabled}"
Keyboard="{Binding Keyboard}"
MaxLength="{Binding MaxLength}"
Placeholder="{Binding Placeholder}"
PlaceholderColor="{Binding PlaceholderColor}"
ReturnType="{Binding ReturnType}"
Text="{Binding Text}"
TextChanged="OnEntryTextChanged"
TextColor="{Binding TextColor}"
Visual="Material" />
<BoxView Grid.Row="0"
Margin="{OnPlatform iOS='0,0,0,-1'}"
BackgroundColor="{Binding EntryBackgroundColor}"
BindingContext="{x:Reference MaterialEntryComponent}"
HorizontalOptions="Start"
VerticalOptions="FillAndExpand"
WidthRequest="16" />
</Grid>
The bulk of the work is being done by the negative left margin on the parent grid, and the width of 16 on the BoxView. I did find out I needed to move the margin of the BoxView down by 1 on iOS to cover the underline.
And the code behind:
using System;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace x.x.x.Controls.MaterialControls
{
/// <summary>
/// Code behind for the Material Entry control.
/// </summary>
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MaterialEntry : Grid
{
#region Event Handlers
/// <summary>
/// Completed event. Fires when the return key on the keyboard is pressed.
/// </summary>
public event EventHandler Completed;
/// <summary>
/// Text changed event. Fires when the text on the entry control is changed.
/// </summary>
public event EventHandler<TextChangedEventArgs> TextChanged;
#endregion
#region Bindable Properties
/// <summary>
/// Bindable property for the entry background color on the view.
/// </summary>
public static readonly BindableProperty EntryBackgroundColorProperty =
BindableProperty.Create(nameof(EntryBackgroundColor), typeof(Color), typeof(MaterialEntry), Color.White);
/// <summary>
/// Bindable property for the font family of the entry on the view..
/// </summary>
public static readonly BindableProperty FontFamilyProperty =
BindableProperty.Create(nameof(FontFamily), typeof(string), typeof(MaterialEntry), default(string));
/// <summary>
/// Bindable property for the font size of the entry on the view..
/// </summary>
public static readonly BindableProperty FontSizeProperty =
BindableProperty.Create(nameof(FontSize), typeof(double), typeof(MaterialEntry), 12.0);
/// <summary>
/// Bindable property for the IsPassword of the entry on the view.
/// </summary>
public static readonly BindableProperty IsPasswordProperty =
BindableProperty.Create(nameof(IsPassword), typeof(bool), typeof(MaterialEntry), false);
/// <summary>
/// Bindable property for the IsSpellCheckEnabled of the entry on the view.
/// </summary>
public static readonly BindableProperty IsSpellCheckEnabledProperty =
BindableProperty.Create(nameof(IsSpellCheckEnabled), typeof(bool), typeof(MaterialEntry), true);
/// <summary>
/// Bindable property for the IsTextPredictionEnabled of the entry on the view.
/// </summary>
public static readonly BindableProperty IsTextPredictionEnabledProperty =
BindableProperty.Create(nameof(IsTextPredictionEnabled), typeof(bool), typeof(MaterialEntry), true);
/// <summary>
/// Bindable property for the keyboard type of the entry on the view.
/// </summary>
public static readonly BindableProperty KeyboardProperty =
BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(MaterialEntry), Keyboard.Default);
/// <summary>
/// Bindable property for the MaxLength of the entry on the view..
/// </summary>
public static readonly BindableProperty MaxLengthProperty =
BindableProperty.Create(nameof(MaxLength), typeof(int), typeof(MaterialEntry), int.MaxValue);
/// <summary>
/// Bindable property for the placeholder text of the entry on the view.
/// </summary>
public static readonly BindableProperty PlaceholderProperty =
BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(MaterialEntry), default(string));
/// <summary>
/// Bindable property for the placeholder text color of the entry on the view.
/// </summary>
public static readonly BindableProperty PlaceholderColorProperty =
BindableProperty.Create(nameof(PlaceholderColor), typeof(Color), typeof(MaterialEntry), Color.Black);
/// <summary>
/// Bindable property for the return command of the entry on the view.
/// </summary>
public static readonly BindableProperty ReturnCommandProperty =
BindableProperty.Create(nameof(ReturnCommand), typeof(ICommand), typeof(Entry), default(ICommand));
/// <summary>
/// Bindable property for the return command parameter of the entry on the view.
/// </summary>
public static readonly BindableProperty ReturnCommandParameterProperty =
BindableProperty.Create(nameof(ReturnCommandParameter), typeof(object), typeof(Entry), default(object));
/// <summary>
/// Bindable property for the return type of the entry on the view.
/// </summary>
public static readonly BindableProperty ReturnTypeProperty =
BindableProperty.Create(nameof(ReturnType), typeof(ReturnType), typeof(Entry), ReturnType.Default);
/// <summary>
/// Bindable property for the text of the entry on the view.
/// </summary>
public static readonly BindableProperty TextProperty =
BindableProperty.Create(nameof(Text), typeof(string), typeof(MaterialEntry), default(string), BindingMode.TwoWay);
/// <summary>
/// Bindable property for the text color of the entry on the view.
/// </summary>
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create(nameof(TextColor), typeof(Color), typeof(MaterialEntry), Color.Black);
#endregion
#region Properties
/// <summary>
/// The background color of the entry control. Default is <see cref="Color.White"/>.
/// </summary>
public Color EntryBackgroundColor
{
get => (Color)GetValue(EntryBackgroundColorProperty);
set => SetValue(EntryBackgroundColorProperty, value);
}
/// <summary>
/// The font family for the entry control to use.
/// </summary>
public string FontFamily
{
get => (string)GetValue(FontFamilyProperty);
set => SetValue(FontFamilyProperty, value);
}
/// <summary>
/// The font size of the entry control. Default is 12.0.
/// </summary>
[TypeConverter(typeof(FontSizeConverter))]
public double FontSize
{
get => (double)GetValue(FontSizeProperty);
set => SetValue(FontSizeProperty, value);
}
/// <summary>
/// Set if the entry field is a password field. Default is false.
/// </summary>
public bool IsPassword
{
get => (bool)GetValue(IsPasswordProperty);
set => SetValue(IsPasswordProperty, value);
}
/// <summary>
/// Set if spell check is enabled on the entry. Default is True.
/// </summary>
public bool IsSpellCheckEnabled
{
get => (bool)GetValue(IsSpellCheckEnabledProperty);
set => SetValue(IsSpellCheckEnabledProperty, value);
}
/// <summary>
/// Set if text prediction is enabled on the entry. Default is True.
/// </summary>
public bool IsTextPredictionEnabled
{
get => (bool)GetValue(IsTextPredictionEnabledProperty);
set => SetValue(IsTextPredictionEnabledProperty, value);
}
/// <summary>
/// The type of keyboard to use for the entry control. Default is <see cref="Keyboard.Default"/>.
/// </summary>
public Keyboard Keyboard
{
get => (Keyboard)GetValue(KeyboardProperty);
set => SetValue(KeyboardProperty, value);
}
/// <summary>
/// The maximum allowed length of input for the entry. Default is <see cref="int.MaxValue"/>.
/// </summary>
public int MaxLength
{
get => (int)GetValue(MaxLengthProperty);
set => SetValue(MaxLengthProperty, value);
}
/// <summary>
/// The text to use for the placeholder.
/// </summary>
public string Placeholder
{
get => (string)GetValue(PlaceholderProperty);
set => SetValue(PlaceholderProperty, value);
}
/// <summary>
/// The color of the placeholder text. Default is <see cref="Color.Black"/>.
/// </summary>
public Color PlaceholderColor
{
get => (Color)GetValue(PlaceholderColorProperty);
set => SetValue(PlaceholderColorProperty, value);
}
/// <summary>
/// The command that fires when the return button on the keyboard is tapped.
/// </summary>
public ICommand ReturnCommand
{
get => (ICommand)GetValue(ReturnCommandProperty);
set => SetValue(ReturnCommandProperty, value);
}
/// <summary>
/// The parameter to pass with the return command.
/// </summary>
public object ReturnCommandParameter
{
get => GetValue(ReturnCommandParameterProperty);
set => SetValue(ReturnCommandParameterProperty, value);
}
/// <summary>
/// The type of return button to display on the keyboard. Default is <see cref="ReturnType.Default"/>.
/// </summary>
public ReturnType ReturnType
{
get => (ReturnType)GetValue(ReturnTypeProperty);
set => SetValue(ReturnTypeProperty, value);
}
/// <summary>
/// The text of the entry.
/// </summary>
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
/// <summary>
/// The color of the text. Default is <see cref="Color.Black"/>.
/// </summary>
public Color TextColor
{
get => (Color)GetValue(TextColorProperty);
set => SetValue(TextColorProperty, value);
}
#endregion
/// <summary>
/// Constructor.
/// </summary>
public MaterialEntry()
{
InitializeComponent();
}
#region Methods
/// <summary>
/// Focuses the entry control.
/// </summary>
public void FocusEntry()
{
MaterialEntryEntry.Focus();
}
private void OnEntryCompleted(object sender, EventArgs e)
{
SendCompleted();
}
private void OnEntryTextChanged(object sender, TextChangedEventArgs e)
{
TextChanged?.Invoke(this, e);
}
private void SendCompleted()
{
if (IsEnabled)
{
Completed?.Invoke(this, EventArgs.Empty);
if (ReturnCommand != null && ReturnCommand.CanExecute(ReturnCommandParameter))
{
ReturnCommand.Execute(ReturnCommandParameter);
}
}
}
private void OnComponentFocused(object sender, FocusEventArgs e)
{
FocusEntry();
}
#endregion
}
}
To use the control, remember to import the namespace it into your view with:
xmlns:material="clr-namespace:x.x.x.Controls.MaterialControls".
Then using it would be something like:
<material:MaterialEntry Placeholder="Do something amazing"
Style="{StaticResource EntryStyle}"
Text="{Binding MyEntryText}" />

WebApi.HelpPage Error when user clicks on a direct link to the description of the object after iis reset

I using nuget package Microsoft.AspNet.WebApi.HelpPage (5.2.3). I was faced with problem.
For example you can use sample:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Web.Http;
namespace WebApi.Controllers
{
[Authorize]
public class TestController : ApiController
{
/// <summary>
/// TestGet
/// </summary>
/// <returns></returns>
public Plan TestGet()
{
var Plan = new Plan();
Plan.TestObjects = new List<TestClass>();
return Plan;
}
}
[DataContract(Namespace = "")]
public class Plan
{
/// <summary>
/// Name
/// </summary>
[DataMember]
public string Name;
/// <summary>
/// The list of TestClass.
/// </summary>
[DataMember]
public List<TestClass> TestObjects;
}
/// <summary>
/// TestObject
/// </summary>
[DataContract(Namespace = "")]
public class TestClass
{
/// <summary>
/// identifier
/// </summary>
[DataMember]
public int Id;
}
}
How reproduce:
Reload IIS.
If a user clicks on a direct link to the description of the object of collection that he gets an error message.
http://localhost:59576/Help/ResourceModel?modelName=TestClass
If a user is moved to the page with the page the owner of the object or method, then there is no error.
http://localhost:59576/Help/Api/POST-api-Test
The cause of the problem is that in action HelpController.ResourceModel occurs incomplete context initialization.

How do I properly get the entity framework to use my composite primary key?

I have a table defined as such:
CREATE TABLE [dbo].[Sitemap](
[EntityId] [int] NOT NULL,
[PageUrl] [nvarchar](400) NOT NULL,
[Frequency] [nvarchar](400) NOT NULL,
[PageType] [nvarchar](400) NOT NULL,
[UpdatedOn] [datetime] NOT NULL,
CONSTRAINT [PK_Sitemap] PRIMARY KEY CLUSTERED
(
[EntityId] ASC,
[PageType] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
I went to my edmx file and did an update from database. It imported everything but didn't mark both fields as a primary key. I tried added the second field as a primary key, but it still won't treat them as composites.
The issue I am having is when I run an update at the table that has a similar entry such as
EntityId = 1, PageType = 'Product',....
and
EntityId = 1, PageType = 'Artist',...
I am getting an error saying:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
How do I get my Model or code to properly use the composite as the primary key? Or do I have to make some kind of composite field to do this?
UPDATE
My Code is a fork from NopCommerce 1.90
As such I have added an interface and service and registered that with the IoC resolver.
I have the following class that for this table:
//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.nopCommerce.com/License.aspx.
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
//
// Contributor(s): _______.
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using NopSolutions.NopCommerce.BusinessLogic.CustomerManagement;
using NopSolutions.NopCommerce.BusinessLogic.Infrastructure;
using NopSolutions.NopCommerce.BusinessLogic.Payment;
using NopSolutions.NopCommerce.BusinessLogic.Promo.Affiliates;
using NopSolutions.NopCommerce.BusinessLogic.Promo.Discounts;
using NopSolutions.NopCommerce.BusinessLogic.Shipping;
using NopSolutions.NopCommerce.BusinessLogic.Tax;
namespace NopSolutions.NopCommerce.BusinessLogic.SEO.Sitemaps
{
/// <summary>
/// Represents a Sitemap
/// </summary>
[Serializable]
public partial class Sitemap : BaseEntity
{
#region Utilities
#endregion
#region Properties
/// <summary>
/// Gets or Sets EntityId (Product ID, Show ID, etc.)
/// </summary>
public int EntityId { get; set; }
/// <summary>
/// Gets or sets the Page Url
/// </summary>
public string PageUrl { get; set; }
/// <summary>
/// Gets of set the Page Frequency (Should be one of the following - Always, Hourly, Daily, Weekly, Monthly, Yearly, Never)
/// </summary>
public string Frequency { get; set; }
/// <summary>
/// Gets or sets the page type. For example: Product, or Show
/// </summary>
public string PageType { get; set; }
/// <summary>
/// Gets or sets the date and time of sitemap entry update
/// </summary>
public DateTime UpdatedOn { get; set; }
#endregion
}
}
Then I have the interface and service:
Interface:
//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.nopCommerce.com/License.aspx.
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
//
// Contributor(s): _______.
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using NopSolutions.NopCommerce.BusinessLogic.CustomerManagement;
using NopSolutions.NopCommerce.BusinessLogic.Payment;
using NopSolutions.NopCommerce.BusinessLogic.Shipping;
using NopSolutions.NopCommerce.Common;
namespace NopSolutions.NopCommerce.BusinessLogic.SEO.Sitemaps
{
/// <summary>
/// Sitemap service
/// </summary>
public partial interface ISiteMapService
{
/// <summary>
/// Gets a Sitemap entry based on url.
/// </summary>
/// <param name="url">Fully Qualified URL (e.g. http://www.onlinesheetmusic.com/default.aspx)</param>
/// <returns></returns>
Sitemap GetSitemap(string url);
/// <summary>
/// Gets the most recent entry to the sitemap table
/// </summary>
/// <returns></returns>
Sitemap GetLastAddedSitemap(string pageType);
/// <summary>
/// Gets a list of Sitemap entries that are in the init state of the given Page Type
/// </summary>
/// <param name="pageType">Page Type</param>
/// <returns></returns>
List<Sitemap> GetInitEntries(string pageType);
/// <summary>
/// Bool to determine if a given pageType has any entries in the init state.
/// </summary>
/// <param name="pageType"></param>
/// <returns></returns>
bool IsInit(string pageType);
void InitSitemap(string pageType, int startProdId = 0);
/// <summary>
/// Inserts a sitemap entry
/// </summary>
/// <param name="order">Order</param>
void InsertSitemap(Sitemap sm);
/// <summary>
/// Updates the order
/// </summary>
/// <param name="order">The order</param>
void UpdateSitemap(Sitemap sm);
}
}
Service:
//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.nopCommerce.com/License.aspx.
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
//
// Contributor(s): _______.
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using NopSolutions.NopCommerce.BusinessLogic.Audit;
using NopSolutions.NopCommerce.BusinessLogic.Caching;
using NopSolutions.NopCommerce.BusinessLogic.Configuration.Settings;
using NopSolutions.NopCommerce.BusinessLogic.CustomerManagement;
using NopSolutions.NopCommerce.BusinessLogic.Data;
using NopSolutions.NopCommerce.BusinessLogic.Directory;
using NopSolutions.NopCommerce.BusinessLogic.Infrastructure;
using NopSolutions.NopCommerce.BusinessLogic.Localization;
using NopSolutions.NopCommerce.BusinessLogic.Messages;
using NopSolutions.NopCommerce.BusinessLogic.Messages.SMS;
using NopSolutions.NopCommerce.BusinessLogic.Payment;
using NopSolutions.NopCommerce.BusinessLogic.Products;
using NopSolutions.NopCommerce.BusinessLogic.Products.Attributes;
using NopSolutions.NopCommerce.BusinessLogic.Profile;
using NopSolutions.NopCommerce.BusinessLogic.Promo.Discounts;
using NopSolutions.NopCommerce.BusinessLogic.QuickBooks;
using NopSolutions.NopCommerce.BusinessLogic.Security;
using NopSolutions.NopCommerce.BusinessLogic.Shipping;
using NopSolutions.NopCommerce.BusinessLogic.Tax;
using NopSolutions.NopCommerce.Common;
using NopSolutions.NopCommerce.Common.Extensions;
using NopSolutions.NopCommerce.Common.Utils;
using NopSolutions.NopCommerce.Common.Utils.Html;
namespace NopSolutions.NopCommerce.BusinessLogic.SEO.Sitemaps
{
/// <summary>
/// Sitemap service
/// </summary>
public partial class SiteMapService : ISiteMapService
{
#region Fields
/// <summary>
/// Object context
/// </summary>
private readonly NopObjectContext _context;
/// <summary>
/// Cache service
/// </summary>
private readonly ICacheManager _cacheManager;
#endregion Fields
#region Ctor
/// <summary>
/// Ctor
/// </summary>
/// <param name="context">Object context</param>
public SiteMapService(NopObjectContext context)
{
this._context = context;
this._cacheManager = new NopRequestCache();
}
#endregion Ctor
#region Utilities
#endregion Utilities
#region Methods
/// <summary>
/// Gets a sitemap entry
/// </summary>
/// <param name="url">The url of the sitempa item</param>
/// <returns>Order</returns>
public Sitemap GetSitemap(string url)
{
if (!url.IsNotNullOrEmpty())
return null;
var query = from sm in _context.Sitemaps
where sm.PageUrl.Contains(url)
select sm;
var sitemap = query.SingleOrDefault();
return sitemap;
}
public Sitemap GetLastAddedSitemap(string pageType)
{
var query = (from sm in _context.Sitemaps
where sm.PageType.Equals(pageType)
orderby sm.UpdatedOn descending
select sm).Take(1);
var sitemap = query.SingleOrDefault();
return sitemap;
}
public List<Sitemap> GetInitEntries(string pageType)
{
var query = (from sm in _context.Sitemaps
where sm.PageType.Equals(pageType)
&& sm.Frequency == "Init"
select sm).Take(500);
return query.ToList();
}
/// <summary>
/// Bool to check if a given type has any entries in the init state.
/// </summary>
/// <param name="pageType">Page Type</param>
/// <returns>True or False</returns>
public bool IsInit(string pageType)
{
var query = (from sm in _context.Sitemaps
where sm.PageType.Equals(pageType)
&& sm.PageUrl.Equals("Init")
select sm).Take(1);
if (query == null)
return true;
else
return false;
}
public void InitSitemap(string pageType, int startProdId = 0)
{
_context.Sp_SitemapInit(pageType, startProdId);
}
/// <summary>
/// Inserts a sitemap entry
/// </summary>
/// <param name="sm">Sitemap Entry to Insert</param>
public void InsertSitemap(Sitemap sm)
{
if (sm == null)
throw new ArgumentNullException("sitemap");
sm.PageUrl = CommonHelper.EnsureNotNull(sm.PageUrl);
sm.PageType = CommonHelper.EnsureNotNull(sm.PageType);
sm.Frequency = CommonHelper.EnsureNotNull(sm.Frequency);
_context.Sitemaps.AddObject(sm);
_context.SaveChanges();
}
/// <summary>
/// Updates a sitemap entry
/// </summary>
/// <param name="sm">Sitemap Entry to update</param>
public void UpdateSitemap(Sitemap sm)
{
if (sm == null)
throw new ArgumentNullException("sitemap");
sm.PageUrl = CommonHelper.EnsureNotNull(sm.PageUrl);
sm.PageType = CommonHelper.EnsureNotNull(sm.PageType);
sm.Frequency = CommonHelper.EnsureNotNull(sm.Frequency);
if(_context.Sitemaps.Any(s => (s.PageUrl == sm.PageUrl || s.EntityId == sm.EntityId)))
{
if (!_context.IsAttached(sm))
_context.Sitemaps.Attach(sm);
}
else
{
_context.Sitemaps.AddObject(sm);
}
_context.SaveChanges();
}
#endregion Methods
#region Properties
/// <summary>
/// Gets a value indicating whether cache is enabled
/// </summary>
public bool CacheEnabled
{
get
{
return IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Cache.OrderManager.CacheEnabled");
}
}
#endregion Properties
}
}
When I call
var sitemapservice = IoC.Resolve<ISiteMapService>();
sitemapservice.InitSitemap("Artist");
var smEntries = sitemapservice.GetInitEntries("Artist");
foreach (Sitemap sm in smEntries)
{
using (MvcMiniProfiler.MiniProfiler.StepStatic("Processing Entry: " + sm.EntityId + "," + sm.PageType))
{
sm.Frequency = "Monthly";
sm.PageUrl = SEOHelper.GetUrl(this.ArtistService.GetArtistById(sm.EntityId), this.SettingManager.StoreUrl);
using (MvcMiniProfiler.MiniProfiler.StepStatic("Updating database"))
{
sitemapservice.UpdateSitemap(sm);
}
curCount++;
}
}
It is supposed to get all the entries that are in the init stage and set them up with the correct url, but for whatever reason I keep getting errors saying An object with the same key already exists in the ObjectStateManager. Though the strange thing is the DB seems to be updating properly it just keeps giving me this error.
I think this is what you are referring to...
public class CollectionItem
{
public int CollectionId { get; set; }
public int ItemId { get; set; }
[RelatedTo(ForeignKey = "CollectionId")]
public Collection Collection { get; set; }
[RelatedTo(ForeignKey = "ItemId")]
public Item Item { get; set; }
}
And use model builder like so
var builder = new ModelBuilder();
// ...
builder.Entity<CollectionItem>().HasKey(p=>new {p.CollectionId, p.ItemId});
// ...
model = builder.CreateModel();
Hope this helps, I have tried to keep the names generic

signalR OnDisconnected() cancel task

When a page loads I start a new task in my hub. This task sends data to a browser updating a certain html elements. When I browse away from the page I want to stop the task.
The problem is that before the task is stopped (due to it's sleep argument), a new tokenSource = new CancellationTokenSource();
is set before the previous instance of this task had a chance to stop.
What i'm trying to do is to have the task stop when browsing away from the page to a different page that is not requiring signalR. BUT maybe, not stop it if it's only a refresh of the same page. Not sure how to do it. To sum it up, I want to guarantee that only 1 instance of this task is running (AND only on the page that requires it/or have a listener)
any info greatly appreciated.
thanks
CODE:
public class TaskActionStatus : Hub
{
#region Static Fields
/// <summary>
/// The token source.
/// </summary>
private static CancellationTokenSource tokenSource;
/// <summary>
/// The url string.
/// </summary>
private static string url = string.Empty;
#endregion
#region Public Methods and Operators
/// <summary>
/// The get tasks status.
/// </summary>
/// <param name="siteId">
/// The site id.
/// </param>
/// <param name="location"></param>
public void GetTasksStatus(int? siteId)
{
var taskRepository = UnityContainerSetup.Container.Resolve<ITaskRepository>();
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
// init task for checking task statuses
var tasksItem = new DownloadTaskItem();
// start task only if at least one listener
if (UserHandler.ConnectedIds.Count < 2 && !taskRepository.IsTasksStatusAsyncRunning())
{
taskRepository.GetTasksStatusAsync(siteId, tasksItem, ct);
// subscribe to event [ listener ]
tasksItem.Changed += this.UpdateTasksStatus;
}
else tokenSource.Cancel();
}
/// <summary>
/// The on connected.
/// </summary>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public override Task OnConnected()
{
UserHandler.ConnectedIds.Add(this.Context.ConnectionId);
return base.OnConnected();
}
/// <summary>
/// The on disconnected.
/// </summary>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public override Task OnDisconnected()
{
UserHandler.ConnectedIds.Remove(this.Context.ConnectionId);
if (UserHandler.ConnectedIds.Count == 0)
{
try
{
tokenSource.Cancel();
}
catch (Exception ex)
{
Log.Error(ex);
}
}
return base.OnDisconnected();
}
/// <summary>
/// The update tasks status.
/// </summary>
/// <param name="sender">
/// The sender.
/// </param>
/// <param name="e">
/// The e.
/// </param>
public void UpdateTasksStatus(object sender, TaskEventArgs e)
{
this.Clients.All.updateMessages(e.Tasks);
}
#endregion
}
/// <summary>
/// The user handler.
/// </summary>
public static class UserHandler
{
#region Static Fields
/// <summary>
/// The connected ids.
/// </summary>
public static HashSet<string> ConnectedIds = new HashSet<string>();
#endregion
}
public bool IsTasksStatusAsyncRunning()
{
if (tasksStatusAsync != null && tasksStatusAsync.Status.Equals(TaskStatus.Running))
{
return true;
}
return false;
}
Moving this line:
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
...
making it this:
if (UserHandler.ConnectedIds.Count < 2)
{
Trace.WriteLine("GetTasksStatus: Starting new task");
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
taskRepository.GetTasksStatusAsync(siteId, tasksItem, ct);
// subscribe to event [ listener ]
tasksItem.Changed += this.UpdateTasksStatus;
}
did it for me. thanks

Resources