- Is
- EqualTo
- NotEqualTo
- GreaterThan
- LessThan
- GreaterThanOrEqualTo
- LessThanOrEqualTo
- Improved required validators:
- RequiredIf
- RequiredIfNot
- RequiredIfTrue
- RequiredIfFalse
- RequiredIfEmpty
- RequiredIfNotEmpty
- RequiredIfRegExMatch
- RequiredIfNotRegExMatch
- In
- NotIn
Owin چیست ؟ قسمت اول
بررسی روش آپلود فایلها در ASP.NET Core
Right click on the folder -> Properties -> Security tab -> Click at Edit button -> Enter `IIS AppPool\DefaultAppPool` user (IIS AppPool\<app_pool_name>) -> Click at Check names -> OK -> Then give it `write` or other permissions.
ساخت لیست سفارشی
ابتدا یک لیست سفارشی بنام ContentSlides ایجاد میکنیم و ستونی از نوع Rich HTML به آن اضافه میکنیم.ایجاد یک پروژه شیرپوینتی از نوع Visual Web Part
سپس یک پروژه شیرپوینت از نوع Visual Web Part در سایتی که لیست فوق در آن قرار دارد میسازیم.
در این مرحله نامگذاریهای پیشفرض ویژوال استودیو که برای ویژوال وبپارت در نظر گرفته را به نام مناسب تغییر میدهیم.
افزودن پلاگین AnythingSlider
ابتدا پلاگین AnythingSlider را از این آدرس دریافت نمایید. سپس فایلهای anythingslider.css, anythingslider-ie.css, jquery.min.js, jquery.anythingslider.js و "default.png " را به ویژوال وبپارت اضافه میکنیم. برای اضافه کردن فایلهای این پلاگین، ابتدا فولدر "Layouts" به پروژه اضافه مینماییم و سپس فایلهای این پلاگین در این فولدر قرار میدهیم.سپس در خط 129 و 155 و 181 فایل anythingslider.css
background: url("../images/default.png") no-repeat;
background: url(“default.png") no-repeat;
در ادامه، بر روی "ContentSliderVisualWebPartUserControl.ascx" دابل کلیک کنید و کد زیر را به آن اضافه میکنیم.
<SharePoint:CssRegistration ID="AnythingSliderCssRegistration" runat="server" Name="/_layouts/ContentSliderWebPart/anythingslider.css"></SharePoint:CssRegistration> <SharePoint:CssRegistration ID="AnythingSliderCssRegistrationIE7" runat="server" Name="/_layouts/ContentSliderWebPart/anythingslider.css" ConditionalExpression="lte IE 7"></SharePoint:CssRegistration> <SharePoint:ScriptLink ID="JqueryScriptLink" runat="server" Name="/_layouts/ContentSliderWebPart/jquery.min.js"></SharePoint:ScriptLink> <SharePoint:ScriptLink ID="AnythingSliderScriptLink" runat="server" Name="/_layouts/ContentSliderWebPart/jquery.anythingslider.js"></SharePoint:ScriptLink>
توجه کنید در کد بالا ما از کنترلهای "SharePointCssRegistration" و "SharePointScriptLink" برای اضافه نمودن فایلهای Css و JavaScript مورد نیاز و هم چنین از خصیصه "ConditionalExpression" برای اضافه کردن فایل "anythingslider-ie.css" برای مرورگر اینترنت اکسپلورر 7 به بالا استفاده کردیم.
ایجاد کوئری برای لیست سفارشی
برای ایجاد کوئری از کتابخانه jQuery بنام SPService که از این آدرس قابل دریافت است، استفاده میکنیم. فایل "jquery.SPServices.min.js" موجود در این کتابخانه را همانند سایر فایلهای اضافه شده در قسمت قبل را به پروژه اضافه میکنیم.
برای استفاده از کتابخانه، کد زیر را در user control قسمت فبلی و در ادامه کدهای قبلی وارد میکنیم.
<SharePoint:ScriptLink ID="SPServicesScriptLink" runat="server" Name="/_layouts/ContentSliderWebPart/jquery.SPServices.min.js"></SharePoint:ScriptLink>
و برای ایجاد کوئری کد زیر در user control وارد میکنیم.
<script language="javascript" type="text/javascript"> $(document).ready(function () { $().SPServices({ operation: "GetListItems", async: false, listName: "ContentSlides", CAMLViewFields: "<ViewFields<FieldRef Name='SlidesContent' /></ViewFields>", completefunc: function (xData, Status) { $(xData.responseXML).SPFilterNode("z:row").each(function () { var liHtml = "<li>" + $(this).attr("ows_SlidesContent") + "</li>"; $("#slider").append(liHtml); }); } }); /*-- Initialize AnythingSlider plugin --*/ $('#slider').anythingSlider(); }); </script> <ul id="slider" />
وظیفه این کد انجام کوئری بر روی لیست "ContentSlides" و ایجاد ساختار یک لیست جهت نمایش اسلایدها میباشد که آیتمهای این لیست مقادیر ستون
"Slides Content" میباشد، شناسه این لیست "Slider" است.
توجه کنید: ما میتوانیم CAML Queryهای پیشرفتهای برای اعمال فیلتر مناسب و چیدمان اسلایدها استفاده کنیم.
در ادامه، برای مقدار دهی اولیه به پلاگین بوسیله فراخوانی تابع
$('#slider').anythingSlider();
انجام میشود.
در پایان براحتی با Deploy نمودن Solution، امکان استفاده از وب پارت مهیاست.
برای دریافت کد این پروژه از این آدرس استفاده کنید.
Public Class User { public string Id { get; set; } public string PhoneNumber { get; set; } public Dictionary<string, App> Apps { get; set; } } public class App { public string FirstName { get; set; } public string LastName { get; set; } public string UserName { get; set; } public List<string> Roles { get; set; } public List<String> Messages { get; set; } public String AdressId { get; set; } public bool IsActive { get; set; } = true; [JsonIgnore] public string DisplayName => $"{FirstName} {LastName}"; }
services.AddSingleton<IDocumentStore>(serviceProvider => { var store = new DocumentStore() { Urls = new[] { "http://192.168.1.10:8080" }, Database = "AccountingSystem", }.Initialize(); return store; }); services.AddScoped<IAsyncDocumentSession>(serviceProvider => { var store = serviceProvider.GetRequiredService<IDocumentStore>(); return store.OpenAsyncSession(); });
var user = new User { PhoneNumber = user.PhoneNumber }; user.Apps.Add(appCode, new ActiveApp { FirstName = "عبدالصالح", LastName = "کاشانی", UserName = abdossaleh, IsActive = true, RolesId = new List<string>{"Admin"} }); await _documentSession.StoreAsync(user); await _documentSession.SaveChangesAsync()
var user = await _documentSession.LoadAsync<User>("Users/131-A");
_documentSession.Advanced.Patch<User, string>("Users/131-A", u => u.PhoneNumber , "09131110000");
_documentSession.Advanced.Patch<User, string>("Users/131-A", u => u.Apps["59"].RolesId , r => r.Add("Admin"));
_documentSession.Advanced.Increment<User, int>("Users/131-A", x => x.TestProp, 10);
_documentSession.Advanced.Defer(new PatchCommandData("Users/131-A", null, new PatchRequest() { Script = $@"this.Apps[args.appCode] = args.app", Values = { {"appCode", appCode}, {"app", new ActiveApp { FirstName = "عبدالصالح", LastName = "کاشانی", UserName = abdossaleh, RolesId = new List<string>{"Admin"} } } } }, null));
Script = "this.Apps[args.app].Roles.splice(args.index,0,args.role)", Values = { { "index": 1 // مکانی که میخواهیم عملیات انجام شود "app", 59 "role", "User" } }
splice(args.index,1,args.role)
Script = @"this.Roles= this.Apps[args.app].Roles.filter(role=> role != args.role);", Values = { {"app", 59} {"role", "User"} }
smc.version = "0"
defaults write com.apple.finder AppleShowAllFiles YES
defaults write com.apple.CoreSimulator.IndigoFramebufferServices FramebufferEmulationHint 1
امکان تست بر روی بر روی آخرین نسخه iOS یعنی 12 بر روی iPhone 5s تا iPhone XS Max وجود دارد. علاوه بر این میتوانید iOS 12 را روی iPad نسل پنج و شش و iPad Air 1 و 2 و iPad Pro تست کنید. اگر قصد تست روی نسخههای قدیمیتر iOS، چون iOS 11 یا سایر دستگاهها را دارید، باید ابتدا در XCode، از منوی Window به Devices and simulators بروید و در تب Simulators روی + کلیک کنید. در قسمت OS version میتوانید نسخههای قدیمیتر را دانلود کنید یا برای Apple TV و Apple Watch نیز Simulator بسازید.
برنامه را روی iPhone 6 یا یک گوشی سبک و ساده دیگر گذاشته و برنامه را اجرا کنید و تست بگیرید. دقت کنید که Simulator روی ویندوز اجرا میشود و نیازی به سوئیچ مداوم بین ویندوز و Mac نیست. ولی اگر Simulator روی ویندوز از لحاظ UI ای عملکرد مناسبی را نداشت، در ویژوال استودیو به منوی Tools رفته و از Options > Xamarin > iOS settings تیک Remote simulator to Windows را بردارید که باعث میشود Simulator در Mac اجرا شود. در هر بار عوض کردن Simulator از گوشی ای به گوشی دیگر، پروژه را Clean - Rebuild کنید.
در سریهای بعد که ویژوال استودیو را باز میکنید، از منوی Tools > iOS گزینه Pair Mac را بزنید و به Mac خود متصل شوید.
برای اینکه بتوانید روی گوشی تست بگیرید، در همین عکس بالا، به جای iPhoneSimulator، گزینه iPhone را انتخاب کنید. بهتر است گوشی به آخرین نسخه iOS آپدیت شده باشد. همچنین iTunes for windows را نصب کنید تا ابتدا ویندوز، گوشی شما را که با کابل به کامپیوتر وصل کردهاید بشناسد. سپس در VM Ware درخواست کنید که گوشی به جای ویندوز، به Virtual Machine مک شما وصل شود. در قسمت پایین - سمت راست VM Ware برای هر سخت افزار متصل به کامپیوتر، یک گزینه هست که آنهایی که پر رنگ هستند، سخت افزارهای متصل به Virtual Mac بوده و کمرنگها را Mac نمیبیند. روی سخت افزار گوشی خود کلیک کنید و Connect را بزنید. حال باید بتوانید در iTunes موجود در Mac، اطلاعات مربوط به گوشی خود را مشاهده کنید.
به ویژوال استودیو برگشته و در قسمت Properties پروژه XamApp.iOS، به تب iOS Bundle signing رفته و ضمن انتخاب Automatic provisioning، در قسمت Team، تیم خود را انتخاب کنید. این Team را در زمان ساخت Apple Developer account ایجاد کردهاید و همانطور که قبلا در این آموزش گفته شد، اگر در ویژوال استودیو با آن لاگین کرده باشید، میتوانید آن را ببینید. در صورتی که Apple Developer account ندارید، بر اساس این آموزش پیش بروید.
زمانیکه برنامه را روی گوشی اجرا میکنید، ممکن است در Mac دیالوگ گرفتن نام کاربری و رمز عبور کاربر Mac باز شود، پس نیم نگاهی به آن داشته باشید. پس از اولین اجرای موفق روی گوشی میتوانید در XCode به منوی Window رفته و سپس Devices & simulators را باز کنید و گوشی خود را در قسمت Devices انتخاب کرده و تیک Connect via network را بزنید تا از این به بعد، بدون کابل نیز بتوانید روی گوشی خود تست کنید. البته گوشی، ویندوز و مک، باید در یک شبکه باشند.
نحوه پابلیش پروژه را در مقاله مربوط به App Center خواهیم نوشت. اما به صورت خلاصه حجم فایل ipa حدود 10 مگ است که شامل تمامی مواردی است که در قسمت Android توضیح دادیم و پروژه نهایی شما حجمی در همین حدود خواهد داشت و با اضافه کردن چندین فرم حجم اضافه نمیشود. همانطور که در قسمت توضیحات پیشرفته پروژه اندروید توضیح دادیم، اینجا نیز از AOT و LLVM برای دستیابی به بالاترین سرعت ممکن کدهای Native استفاده شده و کدهای اضافه از پروژه Link (حذف) میشوند. برای اینکار، در ویژوال استودیو iPhone - Release را انتخاب کنید و پروژه را بیلد کنید. فایل ipa درون Mac در فولدر
Library ▸ Caches ▸ Xamarin ▸ mtbs ▸ builds ▸ XamApp.iOS ▸ e9979ba2348d1c5a87390643d62c4a1b ▸ bin ▸ iPhone ▸ Release ▸ XamApp.iOS.ipa
ساخته میشود که Library فولدری در User شما بوده و مقدار Guid مربوطه، Random است. همچنین XamApp.iOS نام پروژه است.
حالتهای متصور برای عکس بالا عبارتند از [Debug - iPhoneSimulator] و [Debug - iPhone] و [Release - iPhone] که دو تای اول برای تست روی Simulator و Device بوده و حالت سوم برای Release کردن فایل ipa. طبیعی است که تنظیم [Release - Simulator] معنی نمیدهد.
با توجه به اینکه محیط توسعه برنامه را آماده کردهایم، از قسمت بعد، به آموزش کدنویسی خواهیم پرداخت.
var container = new Container(x => { x.Scan(scanner => { scanner.AssemblyContainingType<IOrderHandler>(); // connects `IAccounting` to `Accounting` and `ISales` to `Sales` automatically. scanner.WithDefaultConventions(); }); });
builder.RegisterAssemblyTypes(myAssembly) .Where(t => t.IsAssignableTo<IMyInterface>()) .AsImplementedInterfaces();
دریافت و نصب کتابخانهی کمکی Scrutor
کتابخانهی کمکی Scrutor سورس باز بوده و بستهی NuGet آن توسط یکی از دستورات زیر به پروژه افزوده میشود:
> Install-Package Scrutor > dotnet add package Scrutor
<Project Sdk="Microsoft.NET.Sdk.Web"> <ItemGroup> <PackageReference Include="Scrutor" Version="3.0.2" /> </ItemGroup> </Project>
ثبت و معرفی سادهتر سرویسها بر اساس قواعد نامگذاری آنها توسط Scrutor
فرض کنید تعدادی سرویس را به صورت زیر تعریف کردهاید:
namespace CoreIocServices { public interface IFoo { void Run(); } public class Foo : IFoo { public void Run() { throw new System.NotImplementedException(); } } public interface IBar { void Add(); } public class Bar : IBar { public void Add() { throw new System.NotImplementedException(); } } public interface IBaz { void Stop(); } public class Baz : IBaz { public void Stop() { throw new System.NotImplementedException(); } } }
services.AddScoped<IFoo, Foo>(); services.AddScoped<IBar, Bar>(); services.AddScoped<IBaz, Baz>();
در اینجا در حین تعریف سرویسهای فوق این روش نامگذاری رعایت شدهاست: هر اینترفیس، نامش یک I بیشتر از نام کلاس مشتق شدهی از آن دارد؛ مانند اینترفیس IFoo و کلاس Foo. کتابخانهی StructureMap که در ابتدای بحث معرفی شد، کار اسکن و اتصال یک چنین سرویسهایی را با تعریف scanner.WithDefaultConventions انجام میدهد. معادل آن با Scrutor به صورت زیر است:
namespace CoreIocSample02 { public class Startup { public void ConfigureServices(IServiceCollection services) { services.Scan(scan => //scan.FromCallingAssembly() scan.FromAssemblyOf<IFoo>() .AddClasses() .AsMatchingInterface() .WithScopedLifetime());
- scan.FromAssemblyOf کار اسکن اسمبلی را انجام میدهد که نوع IFoo در آن قرار دارد. اگر از scan.FromCallingAssembly استفاده کنیم، به این معنا است که کار اسکن را دقیقا از همین اسمبلی فراخوان کدهای جاری، شروع کن. اما چون IFoo تعریف شده، در یک پروژه و اسمبلی دیگر قرار دارد، به همین جهت نیاز به ذکر صریح اسمبلی آن نیز هست.
- AddClasses یعنی تمام کلاسهای public, non-abstract را به لیست services اضافه کن.
- AsMatchingInterface یعنی بر اساس قرارداد نامگذاری IClassName و ClassName، اتصالات سرویسها را انجام بده.
بجای آن میتوان از AsImplementedInterfaces نیز استفاده کرد. این حالت برای زمانی مناسب است که یک کلاس، چندین اینترفیس را پیاده سازی کند (مثلا کلاس TestService اینترفیسهای ITestService و IService را پیاده سازی کرده باشد) و علاقمند باشید به ازای هر اینترفیس، یکبار سرویس آن نیز ثبت شود؛ کاری مانند تنظیمات زیر:
services.AddScoped<ITestService, TestService>(); services.AddScoped<IService, TestService>();
- WithScopedLifetime نیز طول عمر این سرویسهای اضافه شده را مشخص میکند. در اینجا میتوان WithTransientLifetime و WithSingletonLifetime را نیز ذکر کرد.
بنابراین همانطور که ملاحظه میکنید، هنوز هم همان سیستم Microsoft.Extensions.DependencyInjection برقرار است؛ اما با وجود متد الحاقی جدید Scan، کار تعاریف سرویسهای برنامه به شدت ساده میشود.
کار با وهلههای کلاسهای سرویسها بجای اینترفیسهای آن توسط Scrutor
میخواهیم مثال سوم قسمت ششم «چگونه بجای اینترفیسها، یک وهله از کلاسی مشخص را از سیستم تزریق وابستگیها درخواست کنیم؟» را توسط Scrutor پیاده سازی کنیم:
namespace CoreIocServices { public interface IService { } public class Service1 : IService { } public class Service2 : IService { } public class Service : IService { } }
services.AddTransient<Service1>(); services.AddTransient<Service2>(); services.AddTransient<Service>();
namespace CoreIocSample02 { public class Startup { public void ConfigureServices(IServiceCollection services) { services.Scan(scan => //scan.FromCallingAssembly() scan.FromAssemblyOf<IService>() .AddClasses() .AsSelf() .WithTransientLifetime());
services.Scan(scan => scan.AddTypes(new[] { typeof(Service1), typeof(Service2) }) .AsSelf() .WithTransientLifetime());
AsSelf: معادل ()<services.AddTransient<TestService است. در این حالت کلاسهایی که اینترفیسی را پیاده سازی نمیکنند و یا در کل مایل هستید که از طریق تزریق وابستگیها در دسترس باشند، میتوان توسط متد AsSelf به سیستم معرفی کرد.
AsSelfWithInterfaces: معادل تنظیمات زیر است:
services.AddSingleton<TestService>(); services.AddSingleton<ITestService>(x => x.GetRequiredService<TestService>()); services.AddSingleton<IService>(x => x.GetRequiredService<TestService>());
روشهای متفاوت اسکن اسمبلیها در Scrutor
Scrutor به همراه روشهای متعددی برای تعریف اسمبلی یا اسمبلیهایی است که باید اسکن شوند و نمونهای از آنرا با FromAssemblyOf بررسی کردیم:
services.Scan(scan => //scan.FromCallingAssembly() scan.FromAssemblyOf<IService>()
الف) FromAssemblyOf<>, FromAssembliesOf : اسمبلی یا اسمبلیهایی که نوع یا نوعهای تعیین شده را به همراه دارند، اسکن میکند.
ب) FromCallingAssembly, FromExecutingAssembly, FromEntryAssembly کار اسکن اسمبلیهای فراخوان، اسمبلی که هم اکنون در حال اجرا است و اسمبلی آغازین برنامه را انجام میدهند.
ج) FromAssemblyDependencies: تمام اسمبلیهایی را که وابستهی به اسمبلی معرفی شدهی به آن هستند، اسکن میکند.
د) FromApplicationDependencies, FromDependencyContext: تمام اسمبلیهایی را که توسط برنامه، ارجاعی به آنها وجود دارند، اسکن میکند.
انتخاب دقیقتر کلاسها و سرویسهای مدنظر توسط Scrutor
شاید عملکرد کلی متد AddClasses مدنظر شما نباشد و نیاز به انتخاب دقیقتری از سرویسهای اسکن شده را داشته باشید؛ برای این مورد نیز Scrutor روشهای زیر را ارائه میدهد. برای مثال خود کلاس AddClasses دارای overloadهای زیر نیز هست:
public interface IImplementationTypeSelector : IAssemblySelector, IFluentInterface { IServiceTypeSelector AddClasses(); IServiceTypeSelector AddClasses(bool publicOnly); IServiceTypeSelector AddClasses(Action<IImplementationTypeFilter> action); IServiceTypeSelector AddClasses(Action<IImplementationTypeFilter> action, bool publicOnly); }
services.Scan(scan => scan .FromAssemblyOf<IService>() .AddClasses(classes => classes.AssignableTo<IService>()) // .AddClasses(classes => classes.InNamespaces("MyApp")) // .AddClasses(classes => classes.Where(type => type.Name.EndsWith("Repository")) .AsImplementedInterfaces() .WithTransientLifetime());
مدیریت جایگزینی سرویسها توسط Scrutor
یکی از مزیتهای طراحی یک برنامه با درنظر گرفتن الگوی تزریق وابستگیها، امکان جایگزین کردن سرویسهای پیشفرض آن با سرویسهای دیگری است. فرض کنید کتابخانهای ارائه شده و از الگوریتم هش کردن X استفاده کردهاست؛ اما شما علاقمندید تا از الگوریتم Y بجای آن استفاده کنید. اگر این کتابخانه وهلهی الگوریتم هش کردن را از طریق تزریق وابستگیها تامین کرده باشد، فقط کافی است در ابتدای معرفی تنظیمات تزریق وابستگیهای آن، سرویس الگوریتم هش کردن موجود را با نمونهی خاص خودتان جایگزین کنید.
اکنون فرض کنید پیش از استفادهی از Scrutor، تعدادی سرویس را به روش متداولی ثبت و معرفی کردهاید:
services.AddTransient<ITransientService, TransientService>(); services.AddScoped<IScopedService, ScopedService>();
public class TransientService : IFooService {} public class AnotherService : IScopedService {}
services.Scan(scan => scan.FromAssemblyOf<IFoo>() .AddClasses() .UsingRegistrationStrategy(RegistrationStrategy.Skip) .AsMatchingInterface() .WithScopedLifetime());
namespace Scrutor { public abstract class RegistrationStrategy { public static readonly RegistrationStrategy Skip; public static readonly RegistrationStrategy Append; protected RegistrationStrategy(); public static RegistrationStrategy Replace(); public static RegistrationStrategy Replace(ReplacementBehavior behavior); public abstract void Apply(IServiceCollection services, ServiceDescriptor descriptor); } }
- حالت Skip آن، سرویسی را تکراری ثبت نمیکند. یعنی اگر سرویسی پیشتر در مجموعهی IServiceCollection موجود بود، مجددا آنرا ثبت نمیکند.
سپس نوبت به متدهای Replace میرسد که یک چنین پارامتری را قبول میکنند:
namespace Scrutor { [Flags] public enum ReplacementBehavior { Default = 0, ServiceType = 1, ImplementationType = 2, All = 3 } }
- در حالت استفادهی از Replace(ReplacementBehavior.ImplementationType)، اگر پیاده سازی کلاسی پیشتر در لیست IServiceCollection ثبت شده باشد، آنرا حذف کرده و سپس نمونهی جدید را ثبت میکند (ثبت سرویس صرفا بر اساس نام کلاس آن).
- حالت Replace(ReplacementBehavior.All) هر دو حالت قبل را با هم شامل میشود.
امکان ترکیب چندین استراتژی جستجو با هم توسط Scrutor
در یک برنامهی واقعی غیرممکن است که بخواهید تمام کلاسها را با یک طول عمر، اسکن و ثبت کنید. برای این منظور میتوان از قابلیت فیلتر کردن کلاسها که در مورد آن بحث شد و همچنین امکان ترکیب زنجیر وار حالتهای مختلف اسکن، استفاده کرد:
services.Scan(scan => scan .FromAssemblyOf<CombinedService>() .AddClasses(classes => classes.AssignableTo<ICombinedService>()) // Filter classes .AsSelfWithInterfaces() .WithSingletonLifetime() .AddClasses(x=> x.AssignableTo(typeof(IOpenGeneric<>))) // Can close generic types .AsMatchingInterface() .AddClasses(x=> x.InNamespaceOf<MyClass>()) .UsingRegistrationStrategy(RegistrationStrategy.Replace()) // Defaults to ReplacementBehavior.ServiceType .AsMatchingInterface() .WithScopedLifetime() .FromAssemblyOf<DatabaseContext>() // Can load from multiple assemblies within one Scan() .AddClasses() .AsImplementedInterfaces() );
تبدیلگر ایران سیستم به یونیکد
من اگر بخوام لیست کاربرایی که یک نقش خاص مثلا "Admin" رو دارن لیست کنم چطور میتونم دسترسی داشته باشم؟